summaryrefslogtreecommitdiffstats
path: root/private/ntos/nbt
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/nbt
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/nbt')
-rw-r--r--private/ntos/nbt/dirs25
-rw-r--r--private/ntos/nbt/inc/ctemacro.h1468
-rw-r--r--private/ntos/nbt/inc/debug.h70
-rw-r--r--private/ntos/nbt/inc/hosts.h279
-rw-r--r--private/ntos/nbt/inc/nbtinfo.h28
-rw-r--r--private/ntos/nbt/inc/nbtnt.h272
-rw-r--r--private/ntos/nbt/inc/nbtprocs.h1451
-rw-r--r--private/ntos/nbt/inc/ntprocs.h845
-rw-r--r--private/ntos/nbt/inc/oscfgnbt.h85
-rw-r--r--private/ntos/nbt/inc/timer.h89
-rw-r--r--private/ntos/nbt/inc/types.h2449
-rw-r--r--private/ntos/nbt/inc/vxddebug.h150
-rw-r--r--private/ntos/nbt/inc/vxdprocs.h1121
-rw-r--r--private/ntos/nbt/makefile.1667
-rw-r--r--private/ntos/nbt/nbt/depend.mk391
-rw-r--r--private/ntos/nbt/nbt/dirs22
-rw-r--r--private/ntos/nbt/nbt/hashtbl.c668
-rw-r--r--private/ntos/nbt/nbt/hndlrs.c4186
-rw-r--r--private/ntos/nbt/nbt/inbound.c4118
-rw-r--r--private/ntos/nbt/nbt/init.c1037
-rw-r--r--private/ntos/nbt/nbt/makefile.16109
-rw-r--r--private/ntos/nbt/nbt/mp/makefile6
-rw-r--r--private/ntos/nbt/nbt/mp/sources27
-rw-r--r--private/ntos/nbt/nbt/name.c10345
-rw-r--r--private/ntos/nbt/nbt/namesrv.c3886
-rw-r--r--private/ntos/nbt/nbt/nbtutils.c2042
-rw-r--r--private/ntos/nbt/nbt/parse.c4140
-rw-r--r--private/ntos/nbt/nbt/proxy.c282
-rw-r--r--private/ntos/nbt/nbt/sources.inc65
-rw-r--r--private/ntos/nbt/nbt/timer.c692
-rw-r--r--private/ntos/nbt/nbt/udpsend.c1742
-rw-r--r--private/ntos/nbt/nbt/up/makefile6
-rw-r--r--private/ntos/nbt/nbt/up/sources27
-rw-r--r--private/ntos/nbt/nbtprocs.h12
-rw-r--r--private/ntos/nbt/nt/autodial.c723
-rw-r--r--private/ntos/nbt/nt/ctestuff.c90
-rw-r--r--private/ntos/nbt/nt/dirs22
-rw-r--r--private/ntos/nbt/nt/driver.c1228
-rw-r--r--private/ntos/nbt/nt/fileio.c384
-rw-r--r--private/ntos/nbt/nt/mp/makefile6
-rw-r--r--private/ntos/nbt/nt/mp/netbt.prf170
-rw-r--r--private/ntos/nbt/nt/mp/sources30
-rw-r--r--private/ntos/nbt/nt/netbt.rc13
-rw-r--r--private/ntos/nbt/nt/netbtkd/kdextlib.c843
-rw-r--r--private/ntos/nbt/nt/netbtkd/kdextlib.h139
-rw-r--r--private/ntos/nbt/nt/netbtkd/makefile6
-rw-r--r--private/ntos/nbt/nt/netbtkd/netbtkd.c369
-rw-r--r--private/ntos/nbt/nt/netbtkd/netbtkd.def8
-rw-r--r--private/ntos/nbt/nt/netbtkd/sources53
-rw-r--r--private/ntos/nbt/nt/ntisol.c4873
-rw-r--r--private/ntos/nbt/nt/ntpnp.c682
-rw-r--r--private/ntos/nbt/nt/ntutil.c2103
-rw-r--r--private/ntos/nbt/nt/registry.c1811
-rw-r--r--private/ntos/nbt/nt/sources.inc71
-rw-r--r--private/ntos/nbt/nt/tdiaddr.c672
-rw-r--r--private/ntos/nbt/nt/tdicnct.c530
-rw-r--r--private/ntos/nbt/nt/tdihndlr.c6286
-rw-r--r--private/ntos/nbt/nt/tdiout.c727
-rw-r--r--private/ntos/nbt/nt/up/makefile6
-rw-r--r--private/ntos/nbt/nt/up/netbt.prf170
-rw-r--r--private/ntos/nbt/nt/up/sources30
-rw-r--r--private/ntos/nbt/nt/winsif.c1390
-rw-r--r--private/ntos/nbt/rules16.mk79
-rw-r--r--private/ntos/nbt/setenv.bat46
-rw-r--r--private/ntos/nbt/tools/h2inc.sed63
-rw-r--r--private/ntos/nbt/vxd.000/makefile37
-rw-r--r--private/ntos/nbt/vxd.000/makeres.bat5
-rw-r--r--private/ntos/nbt/vxd.000/vnbt.mk122
-rw-r--r--private/ntos/nbt/vxd/aaaaaaaa.c2
-rw-r--r--private/ntos/nbt/vxd/chic.c1787
-rw-r--r--private/ntos/nbt/vxd/chicasm.asm122
-rw-r--r--private/ntos/nbt/vxd/cinit.c930
-rw-r--r--private/ntos/nbt/vxd/client.asm427
-rw-r--r--private/ntos/nbt/vxd/ctimer.c237
-rw-r--r--private/ntos/nbt/vxd/cvxdfile.asm186
-rw-r--r--private/ntos/nbt/vxd/cxport.inc4
-rw-r--r--private/ntos/nbt/vxd/depend.mk1279
-rw-r--r--private/ntos/nbt/vxd/dns.c984
-rw-r--r--private/ntos/nbt/vxd/fileio.c476
-rw-r--r--private/ntos/nbt/vxd/limit.txt51
-rw-r--r--private/ntos/nbt/vxd/makefile28
-rw-r--r--private/ntos/nbt/vxd/nbtinfo.c227
-rw-r--r--private/ntos/nbt/vxd/ncb.c529
-rw-r--r--private/ntos/nbt/vxd/newdns.c1019
-rw-r--r--private/ntos/nbt/vxd/pageable.inc36
-rw-r--r--private/ntos/nbt/vxd/rules.mk4
-rw-r--r--private/ntos/nbt/vxd/tdiaddr.c184
-rw-r--r--private/ntos/nbt/vxd/tdicnct.c328
-rw-r--r--private/ntos/nbt/vxd/tdihndlr.c1719
-rw-r--r--private/ntos/nbt/vxd/tdiout.c601
-rw-r--r--private/ntos/nbt/vxd/util.c192
-rw-r--r--private/ntos/nbt/vxd/vfirst.asm79
-rw-r--r--private/ntos/nbt/vxd/vnbt.rcv15
-rw-r--r--private/ntos/nbt/vxd/vnbtd.asm993
-rw-r--r--private/ntos/nbt/vxd/vnbtd.def21
-rw-r--r--private/ntos/nbt/vxd/vnbtd.inc18
-rw-r--r--private/ntos/nbt/vxd/vnbtd.mk318
-rw-r--r--private/ntos/nbt/vxd/vxddebug.c659
-rw-r--r--private/ntos/nbt/vxd/vxdfile.asm314
-rw-r--r--private/ntos/nbt/vxd/vxdisol.c4042
-rw-r--r--private/ntos/nbt/vxd/vxdstub.asm250
-rw-r--r--private/ntos/nbt/vxd/wfw.c694
-rw-r--r--private/ntos/nbt/vxd/wfwasm.asm285
103 files changed, 85029 insertions, 0 deletions
diff --git a/private/ntos/nbt/dirs b/private/ntos/nbt/dirs
new file mode 100644
index 000000000..eac81d999
--- /dev/null
+++ b/private/ntos/nbt/dirs
@@ -0,0 +1,25 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS= \
+ nbt \
+ nt
diff --git a/private/ntos/nbt/inc/ctemacro.h b/private/ntos/nbt/inc/ctemacro.h
new file mode 100644
index 000000000..817628d6c
--- /dev/null
+++ b/private/ntos/nbt/inc/ctemacro.h
@@ -0,0 +1,1468 @@
+//----------------------------------------------------------------------------
+//
+// ctemacro.c
+//
+// This file contains macros for the common transport environment - similar
+// to the way that ctestuff.c contains common procedures.
+//
+#ifndef _CTEMACRO_H_
+#define _CTEMACRO_H_
+
+
+#ifndef VXD
+#define NT 1
+#include <cxport.h>
+#endif
+
+#ifndef VXD
+char LastLockFile[255] ;
+int LastLockLine ;
+char LastUnlockFile[255] ;
+int LastUnlockLine ;
+#endif
+
+//----------------------------------------------------------------------------
+// VOID
+// NTDereferenceObject(
+// PFILE_OBJECT pFileObject
+// )
+
+/*++
+Routine Description:
+
+ This routine dereferences an object.
+
+
+--*/
+#ifdef VXD
+//
+// No equivalent for Vxd
+//
+#define NTDereferenceObject( fileobject )
+#else //VXD
+#define NTDereferenceObject( fileobject ) ObDereferenceObject( fileobject)
+#endif
+
+//----------------------------------------------------------------------------
+// VOID
+// CHECK_PTR(
+// PVOID SpinLock,
+// )
+
+/*++
+Routine Description:
+
+ This routine checks if a ptr points to freed memory
+
+
+--*/
+
+#if DBG
+#define CHECK_PTR(_Ptr) \
+ ASSERT((ULONG)((PULONG)_Ptr + 16) != 0xd1000000);
+#else
+
+#define CHECK_PTR(_Ptr)
+#endif
+
+
+#ifndef VXD
+/*++
+ This macro verifies that an IRP passed to IoCallDriver() is
+ set up to call the CompletionRoutine in all cases.
+--*/
+#if DBG
+#define CHECK_COMPLETION(__pIrp)\
+ {\
+ PIO_STACK_LOCATION __pIrpSp = IoGetNextIrpStackLocation(__pIrp);\
+ BOOL CompletionWillBeCalled =\
+ ( __pIrpSp->Control & ( SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL ) )\
+ == ( SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL );\
+ ASSERT ( CompletionWillBeCalled );\
+ }
+#else // DBG
+#define CHECK_COMPLETION(__pIrp)
+#endif // DBG
+#endif // VXD
+
+//
+// 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.
+//
+//--
+
+ // Used in the conversion of 100ns times to milliseconds.
+static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
+
+#define SHIFT10000 13
+extern LARGE_INTEGER Magic10000;
+
+#define CTEConvert100nsToMilliseconds(HnsTime) \
+ RtlExtendedMagicDivide((HnsTime), Magic10000, SHIFT10000)
+
+//----------------------------------------------------------------------------
+//
+// CTELockHandle
+//
+
+#ifndef VXD
+
+ //
+ // The Spinlock structure is different between the NT driver and the VXD
+ // driver. This macro is defined in cxport.h when compiling as a VXD.
+ //
+ #define CTELockHandle KIRQL
+#endif
+
+//----------------------------------------------------------------------------
+// VOID
+// CTESpinLock(
+// tCONNECTELE Structure,
+// CTELockHandle OldIrqLevel
+// )
+
+/*++
+Routine Description:
+
+ This Routine acquires a spin lock.
+
+Arguments:
+
+ Size - the number of bytes to allocate
+
+Return Value:
+
+ PVOID - a pointer to the memory or NULL if a failure
+
+--*/
+#ifndef VXD
+#if DBG
+#define CTESpinLock(DataStruct,OldIrqLevel) \
+{ \
+ AcquireSpinLockDebug(&(DataStruct)->SpinLock,&OldIrqLevel,(DataStruct)->LockNumber); \
+ strcpy( LastLockFile, __FILE__ ) ; \
+ LastLockLine = __LINE__ ; \
+}
+#else
+#define CTESpinLock(DataStruct,OldIrqLevel) \
+{ \
+ CTEGetLock(&(DataStruct)->SpinLock,&(OldIrqLevel)); \
+}
+#endif
+#else
+#ifdef DEBUG
+
+#define CTESpinLock(DataStruct,OldIrqLevel) \
+{ \
+ CTEGetLock( &(DataStruct)->SpinLock, &OldIrqLevel ) ; \
+}
+
+#else
+#define CTESpinLock(DataStruct,OldIrqLevel)
+#endif // !DEBUG
+#endif
+
+
+//----------------------------------------------------------------------------
+// VOID
+// CTESpinFree(
+// PVOID SpinLock,
+// CTELockHandle OldIrqLevel
+// )
+/*++
+Routine Description:
+
+ This Routine releases a spin lock.
+
+Arguments:
+
+ Size - the number of bytes to allocate
+
+Return Value:
+
+ PVOID - a pointer to the memory or NULL if a failure
+
+--*/
+
+#ifndef VXD
+#if DBG
+#define CTESpinFree(DataStruct,OldIrqLevel) \
+{ \
+ strcpy( LastUnlockFile, __FILE__ ) ; \
+ LastUnlockLine = __LINE__ ; \
+ FreeSpinLockDebug(&(DataStruct)->SpinLock,OldIrqLevel,(DataStruct)->LockNumber); \
+}
+#else
+#define CTESpinFree(DataStruct,OldIrqLevel) \
+{ \
+ CTEFreeLock((PKSPIN_LOCK)(&(DataStruct)->SpinLock),(OldIrqLevel)); \
+}
+#endif
+#else
+#ifdef DEBUG
+
+#define CTESpinFree(DataStruct,OldIrqLevel) \
+{ \
+ CTEFreeLock( &(DataStruct)->SpinLock, OldIrqLevel ) ; \
+}
+
+#else
+#define CTESpinFree(DataStruct,OldIrqLevel)
+#endif
+#endif
+//----------------------------------------------------------------------------
+// VOID
+// CTESpinLockAtDpc(
+// tCONNECTELE Structure
+// )
+
+/*++
+Routine Description:
+
+ This Routine acquires a spin lock.
+
+Arguments:
+
+ Size - the number of bytes to allocate
+
+Return Value:
+
+ PVOID - a pointer to the memory or NULL if a failure
+
+--*/
+
+#ifndef VXD
+#if DBG
+#define CTESpinLockAtDpc(DataStruct) \
+{ \
+ AcquireSpinLockAtDpcDebug(&(DataStruct)->SpinLock,(DataStruct)->LockNumber);\
+ strcpy( LastLockFile, __FILE__ ) ; \
+ LastLockLine = __LINE__ ; \
+}
+#else // DBG
+#define CTESpinLockAtDpc(DataStruct) \
+{ \
+ CTEGetLockAtDPC((PKSPIN_LOCK)(&(DataStruct)->SpinLock), 0); \
+}
+#endif // DBG
+#else // VXD
+#define CTESpinLockAtDpc(DataStruct)
+#endif // VXD
+
+
+//----------------------------------------------------------------------------
+// VOID
+// CTESpinFreeAtDpc(
+// PVOID SpinLock,
+// CTELockHandle OldIrqLevel
+// )
+/*++
+Routine Description:
+
+ This Routine releases a spin lock.
+
+Arguments:
+
+ Size - the number of bytes to allocate
+
+Return Value:
+
+ PVOID - a pointer to the memory or NULL if a failure
+
+--*/
+
+#ifndef VXD
+#if DBG
+#define CTESpinFreeAtDpc(DataStruct) \
+{ \
+ strcpy( LastUnlockFile, __FILE__ ) ; \
+ LastUnlockLine = __LINE__ ; \
+ FreeSpinLockAtDpcDebug(&(DataStruct)->SpinLock,(DataStruct)->LockNumber);\
+}
+#else // DBG
+#define CTESpinFreeAtDpc(DataStruct) \
+{ \
+ CTEFreeLockFromDPC((PKSPIN_LOCK)(&(DataStruct)->SpinLock), 0); \
+}
+#endif // DBG
+#else // VXD
+#define CTESpinFreeAtDpc(DataStruct)
+#endif // VXD
+
+
+//----------------------------------------------------------------------------
+//
+// VOID
+// CTEVerifyHandle(
+// IN PVOID pDataStruct,
+// IN ULONG Verifier,
+// IN VOID TypeofStruct,
+// OUT NTSTATUS *pRet
+// )
+/*++
+Routine Description:
+
+ This Routine checks that a handle pts to a data structure with the
+ correct verifier in it.
+
+Arguments:
+
+ Size - the number of bytes to allocate
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+#ifndef VXD
+#if DBG
+#define CTEVerifyHandle(_pDataStruct,_Verifier,_TypeofStruct,_ret) \
+{ \
+ if ((_pDataStruct) && \
+ ((((_TypeofStruct *)(_pDataStruct))->Verify) == (_Verifier))) \
+ *_ret=STATUS_SUCCESS; \
+ else \
+ { \
+ ASSERTMSG("Invalid Handle Passed to Nbt",0); \
+ return(STATUS_INVALID_HANDLE); \
+ } \
+}
+#else
+#define CTEVerifyHandle(_pDataStruct,_Verifier,_TypeofStruct,_ret)
+#endif // DBG
+
+#else
+#define CTEVerifyHandle(_pDataStruct,_Verifier,_TypeofStruct,_ret) \
+{ \
+ if ((((_TypeofStruct *)(_pDataStruct))->Verify) == (_Verifier)) \
+ *_ret=STATUS_SUCCESS; \
+ else \
+ return(STATUS_INVALID_HANDLE); \
+}
+#endif
+
+//----------------------------------------------------------------------------
+//
+// VOID
+// CTEIoComplete( IN CTE_IRP * pIrp,
+// IN NTSTATUS StatusCompletion,
+// IN ULONG cbBytes
+// );
+//
+/*++
+Routine Description:
+
+ Completes the requested IO packet. For NT this involves calling the IO
+ subsytem. As a VxD, the Irp is a pointer to the NCB so we set the status
+ variables appropriately and call the post routine if present.
+
+Arguments:
+
+ pIrp - Packet to complete
+ StatusCompletion - Status of the completion
+ cbBytes - Dependent on the type of IO
+
+Return Value:
+
+--*/
+#ifndef VXD
+
+#define PCTE_MDL PMDL
+#define CTE_IRP IRP
+#define PCTE_IRP PIRP
+#define CTE_ADDR_HANDLE PFILE_OBJECT
+
+#define CTEIoComplete( pIrp, StatusCompletion, cbBytes ) \
+ NTIoComplete( pIrp, StatusCompletion, cbBytes )
+
+#else
+#define PCTE_MDL PVOID
+#define CTE_IRP NCB
+#define PCTE_IRP PNCB
+#define PIRP PNCB
+#define CTE_ADDR_HANDLE PVOID
+#define PFILE_OBJECT CTE_ADDR_HANDLE
+
+#define CTEIoComplete( pIrp, StatusCompletion, cbBytes ) \
+ VxdIoComplete( pIrp, StatusCompletion, cbBytes )
+
+#endif
+
+//----------------------------------------------------------------------------
+//
+// ULONG
+// CTEMemCmp( PVOID S1, PVOID S2, ULONG Length )
+//
+/*++
+Routine Description:
+
+ Compares two memory regions and returns the byte count at which the
+ compare failed. The return value will equal Length if the memory
+ regions are identical.
+
+Arguments:
+
+ S1, S2 - Memory source 1 and 2 to compare
+ Length - Count of bytes to compare
+
+Return Value:
+
+--*/
+//
+// CXPORT.H defines this macro differntly and they did it after we had
+// it here, so undef their definition so we can use ours without getting
+// warnings.
+//
+#undef CTEMemCmp
+
+#ifndef VXD
+#define CTEMemCmp( S1, S2, Length ) RtlCompareMemory( (S1), (S2), (Length) )
+#else
+//
+// Same thing as RtlCompareMemory except avoid standard call decoration
+//
+#define CTEMemCmp( S1, S2, Length ) VxdRtlCompareMemory( (S1), (S2), (Length) )
+#endif
+
+//----------------------------------------------------------------------------
+//
+// LOGICAL
+// CTEMemEqu( PVOID S1, PVOID S2, ULONG Length )
+//
+/*++
+Routine Description:
+
+ Compares two memory regions and returns a value of TRUE is the regions
+ match. Otherwise, FALSE is returned.
+
+Arguments:
+
+ S1, S2 - Memory source 1 and 2 to compare
+ Length - Count of bytes to compare
+
+Return Value:
+
+--*/
+
+#ifndef VXD
+#define CTEMemEqu( S1, S2, Length ) RtlEqualMemory( (S1), (S2), (Length) )
+#else
+//
+// Same thing as RtlEqualMemory except avoid standard call decoration
+//
+#define CTEMemEqu( S1, S2, Length ) ( VxdRtlCompareMemory( (S1), (S2), (Length) ) == (Length) )
+#endif
+
+//----------------------------------------------------------------------------
+//
+// Define away any try and except clauses when we are a VXD
+//
+
+#ifndef VXD
+#define CTE_try try
+#define CTE_except except
+#else
+#define CTE_try
+#define CTE_except( x ) if ( 0 )
+#endif
+
+//
+// Misc. memory routines that get mapped when compiling as a VXD
+//
+
+#ifdef VXD
+#define CTEZeroMemory( pDest, uLength ) CTEMemSet( pDest, 0, uLength )
+#define CTEMemFree( p ) CTEFreeMem( p )
+#endif
+//----------------------------------------------------------------------------
+/*++
+ PVOID
+CTEAllocMem(
+ USHORT Size
+ )
+Routine Description:
+
+ This Routine allocates memory for NT drivers by calling ExAllocatePool
+ It uses the definition of CTEAllocMem from cxport.h
+
+Arguments:
+
+ Size - the number of bytes to allocate
+
+Return Value:
+
+ PVOID - a pointer to the memory or NULL if a failure
+
+--*/
+
+#ifndef VXD
+#ifdef POOL_TAGGING
+#undef ExAllocatePool
+#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,' tbN')
+#ifdef DBGMEMNBT
+#undef CTEAllocMem
+#define CTEAllocMem( Size) CTEAllocMemDebug( (Size), NULL, (PUCHAR)__FILE__,(ULONG)__LINE__ )
+#undef CTEFreeMem
+#define CTEFreeMem( pBuffer) CTEAllocMemDebug( 0,(pBuffer),(PUCHAR)__FILE__,(ULONG)__LINE__ )
+#endif
+#endif
+#endif
+
+#ifndef VXD
+#ifdef POOL_TAGGING
+#define NBT_TAG(x) (((x)<<24)|'\0tbN')
+#define NbtAllocMem(size,__tag__) ExAllocatePoolWithTag(NonPagedPool,(size),(__tag__))
+#else // POOL_TAGGING
+#define NBT_TAG(x) 0
+#define NbtAllocMem(size,__tag__) ExAllocatePool(NonPagedPool,(size))
+#endif // POOL_TAGGING
+#else // POOL_TAGGING
+#define NBT_TAG(x) 0
+#define NbtAllocMem(size,__tag__) CTEAllocMem((size))
+#endif // VXD
+
+#ifdef VXD
+#ifdef DEBUG
+#undef CTEAllocMem
+#define CTEAllocMem DbgAllocMem
+#undef CTEFreeMem
+#define CTEFreeMem DbgFreeMem
+#undef CTEMemFree
+#define CTEMemFree DbgFreeMem
+PVOID DbgAllocMem( DWORD ReqSize );
+VOID DbgFreeMem( PVOID pBufferToFree );
+VOID DbgMemCopy( PVOID pDestBuf, PVOID pSrcBuf, ULONG Length );
+#endif
+#endif
+
+//----------------------------------------------------------------------------
+/*++
+ PVOID
+CTEAllocInitMem(
+ ULONG Size
+ )
+Routine Description:
+
+ This Routine allocates memory and if nbt is a Vxd and it's called during
+ DeviceInit time, will refill the heap and retry the allocation before
+ failing.
+
+Arguments:
+
+ Size - the number of bytes to allocate
+
+Return Value:
+
+ PVOID - a pointer to the memory or NULL if a failure
+
+--*/
+
+#ifndef VXD
+#define CTEAllocInitMem(Size) \
+ ExAllocatePool(NonPagedPool, Size)
+#endif
+
+//----------------------------------------------------------------------------
+/*++
+ VOID
+CTEMemFree(
+ PVOID pMem
+ )
+Routine Description:
+
+ This Routine frees memory for NT drivers by calling ExFreePool
+
+Arguments:
+
+ pMem - ptr to memory
+
+Return Value:
+
+ NONE
+
+--*/
+#ifndef VXD
+#define CTEMemFree(pMem) \
+{ \
+ IF_DBG(NBT_DEBUG_MEMFREE) \
+ KdPrint(("pmemfree = %X,lin %d in file %s\n",pMem,__LINE__,__FILE__)); \
+ CTEFreeMem(pMem); \
+}
+#endif
+
+//----------------------------------------------------------------------------
+/*++
+ VOID
+CTEZeroMemory(
+ PVOID pDest,
+ ULONG uLength
+ )
+Routine Description:
+
+ This Routine sets memory to a single byte value
+
+Arguments:
+
+ pDest - dest address
+ uLength - number to zero
+
+Return Value:
+
+ NONE
+
+--*/
+
+#ifndef VXD
+#define CTEZeroMemory(pDest,uLength) \
+ RtlZeroMemory(pDest,uLength)
+#endif
+
+//----------------------------------------------------------------------------
+/*++
+NTSTATUS
+CTEReadIniString(
+ HANDLE ParmHandle,
+ LPTSTR KeyName,
+ LPTSTR * ppStringBuff
+ )
+Routine Description:
+
+ This routine retrieves a string from the users configuration profile
+
+Arguments:
+
+ ParmHandle - Registry handle
+ KeyName - Name of value to retrieve
+ ppStringBuff - Pointer to allocated buffer containing found string
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+#ifndef VXD
+#define CTEReadIniString( ParmHandle, KeyName, ppStringBuff ) \
+ NTReadIniString( ParmHandle, KeyName, ppStringBuff )
+#else
+#define CTEReadIniString( ParmHandle, KeyName, ppStringBuff ) \
+ VxdReadIniString( KeyName, ppStringBuff )
+#endif
+
+//----------------------------------------------------------------------------
+/*++
+ULONG
+CTEReadSingleHexParameter(
+ HANDLE ParmHandle,
+ LPTSTR KeyName,
+ ULONG Default,
+ ULONG Minimum
+ )
+Routine Description:
+
+ This routine retrieves a value in hex from the .ini file or registry
+
+Arguments:
+
+ ParmHandle - Registry handle
+ KeyName - Name of value to retrieve
+ Default - Default value if not present
+ Minimum - Minimum value if present
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+#ifndef VXD
+#define CTEReadSingleIntParameter( ParmHandle, KeyName, Default, Minimum ) \
+ NbtReadSingleParameter( ParmHandle, KeyName, Default, Minimum )
+
+#define CTEReadSingleHexParameter( ParmHandle, KeyName, Default, Minimum ) \
+ NbtReadSingleParameter( ParmHandle, KeyName, Default, Minimum )
+#else
+#define CTEReadSingleIntParameter( ParmHandle, KeyName, Default, Minimum ) \
+ GetProfileInt( ParmHandle, KeyName, Default, Minimum )
+
+#define CTEReadSingleHexParameter( ParmHandle, KeyName, Default, Minimum ) \
+ GetProfileHex( ParmHandle, KeyName, Default, Minimum )
+#endif
+
+//----------------------------------------------------------------------------
+//
+// REFERENCE_LOWERCONN(pLowerConn)
+//
+/*++
+Routine Description:
+
+ Increments the reference count on the LowerConnection and the Connection
+ Element
+
+Arguments:
+
+ pLowerConn - Lower connection ptr
+
+Return Value:
+ None
+--*/
+
+#define REFERENCE_LOWERCONN( _pLowerConn ) \
+{ \
+ IF_DBG(NBT_DEBUG_REF) \
+ KdPrint(("Nbt:LowerConn Reference= %X, Incrementing...\n",\
+ _pLowerConn->RefCount)); \
+ InterlockedIncrement(&_pLowerConn->RefCount); \
+}
+
+//----------------------------------------------------------------------------
+//
+// DEREFERENCE_LOWERCONN(pLowerConn)
+//
+/*++
+Routine Description:
+
+ Decrements the reference count on the LowerConnection and the Connection
+ Element
+
+Arguments:
+
+ pLowerConn - Lower connection ptr
+
+Return Value:
+ None
+--*/
+
+#define DEREFERENCE_LOWERCONN( _pLowerConn ) \
+{ \
+ IF_DBG(NBT_DEBUG_REF) \
+ KdPrint(("Nbt:LowerConn Reference= %X, Decrementing...\n",\
+ _pLowerConn->RefCount)); \
+ InterlockedDecrement(&_pLowerConn->RefCount); \
+}
+
+//----------------------------------------------------------------------------
+//
+// CTEExInitializeResource(Resource)
+//
+/*++
+Routine Description:
+
+ Initializes the Resource structure by calling an excutive support routine.
+
+Arguments:
+
+
+Return Value:
+
+ None
+
+--*/
+#ifndef VXD
+#define CTEExInitializeResource( _Resource ) \
+ ExInitializeResource(_Resource)
+#else
+#define CTEExInitializeResource( _Resource )
+#endif
+
+//----------------------------------------------------------------------------
+//
+// CTEExAcquireResourceExclusive(Resource,Wait)
+//
+/*++
+Routine Description:
+
+ Acquires the Resource by calling an excutive support routine.
+
+Arguments:
+
+
+Return Value:
+
+ None
+
+--*/
+#ifndef VXD
+#define CTEExAcquireResourceExclusive( _Resource, _Wait ) \
+ ExAcquireResourceExclusive(_Resource,_Wait)
+#else
+#define CTEExAcquireResourceExclusive( _Resource, _Wait )
+#endif
+
+//----------------------------------------------------------------------------
+//
+// CTEExReleaseResource(Resource)
+//
+/*++
+Routine Description:
+
+ Releases the Resource by calling an excutive support routine.
+
+Arguments:
+
+
+Return Value:
+
+ None
+
+--*/
+#ifndef VXD
+#define CTEExReleaseResource( _Resource ) \
+ ExReleaseResource(_Resource)
+#else
+#define CTEExReleaseResource( _Resource )
+
+#endif
+
+//----------------------------------------------------------------------------
+//
+// PUSH_LOCATION(Spot)
+//
+/*++
+Routine Description:
+
+ This macro is used for debugging the receive code. It puts a byte value
+ into a circular list of byte values so that previous history can be traced
+ through the receive code.
+
+Arguments:
+
+ Spot - the location to put in the list
+
+Return Value:
+
+ None
+
+--*/
+#if DBG
+extern unsigned char pLocBuff[256];
+extern unsigned char CurrLoc;
+#define PUSH_LOCATION( _Spot) \
+{ \
+ if (++CurrLoc == 256) \
+ { \
+ CurrLoc = 0; \
+ } \
+ pLocBuff[CurrLoc] = _Spot; \
+}
+#else
+#define PUSH_LOCATION( _Spot )
+#endif
+
+#if DBG
+extern unsigned char Buff[256];
+extern unsigned char Loc;
+#define LOCATION( _Spot) \
+{ \
+ if (++Loc == 256) \
+ { \
+ Loc = 0; \
+ } \
+ Buff[Loc] = _Spot; \
+}
+#else
+#define LOCATION( _Spot )
+#endif
+
+//----------------------------------------------------------------------------
+//
+// CTEQueueForNonDispProcessing( pTracker,
+// pClientContext,
+// ClientCompletion,
+// CallBackRoutine
+// pDeviceContext) ;
+//
+/*++
+Routine Description:
+
+ This macro queues a request for a callback that can't be performed in
+ the current context (such as dispatch processing).
+
+ In NT, this calls NTQueueToWorkerThread.
+
+ As a VxD, we schedule an event that calls the specified routine.
+
+Arguments:
+
+ pTracker - pointer to a tDGRAM_SEND_TRACKING structure (or NULL).
+ pClietContext - Context to pass to CallBackRoutine
+ ClientCompletion -
+ CallBackRoutine - Procedure to call at outside the current context
+
+Return Value:
+
+ STATUS_SUCCESS if successful, error code otherwise
+
+--*/
+#ifndef VXD
+#define CTEQueueForNonDispProcessing( pTracker, \
+ pClientContext, \
+ ClientCompletion, \
+ CallBackRoutine, \
+ pDeviceContext) \
+ NTQueueToWorkerThread( pTracker, pClientContext, ClientCompletion, \
+ CallBackRoutine, pDeviceContext )
+#else
+#define CTEQueueForNonDispProcessing( pTracker, \
+ pClientContext, \
+ ClientCompletion, \
+ CallBackRoutine, \
+ pDeviceContext) \
+ VxdScheduleDelayedCall( pTracker, pClientContext, ClientCompletion, \
+ CallBackRoutine, pDeviceContext )
+#endif
+
+//----------------------------------------------------------------------------
+//
+// CTESystemUpTime( OUT PTIME pTime );
+//
+/*++
+Routine Description:
+
+ This macro returns the current system time in clock tics or whatever
+ in the value pTime. For NT this is a Large Integer. For the VXD it is
+ a ULONG.
+
+Arguments:
+
+ pTime
+
+Return Value:
+
+ NONE
+--*/
+#ifndef VXD
+#define CTESystemTime LARGE_INTEGER
+#define CTEQuerySystemTime( _Time ) \
+ KeQuerySystemTime( &(_Time) )
+
+// the lower 4 bits appear to be zero always...!!
+#define RandomizeFromTime( Time, Mod ) \
+ ((Time.LowTime >> 8) % Mod)
+#else
+#define CTESystemTime ULONG
+#define CTEQuerySystemTime( _Time ) \
+ _Time = CTESystemUpTime()
+#define RandomizeFromTime( Time, Mod ) \
+ ((Time >> 4) % Mod)
+#endif
+
+//----------------------------------------------------------------------------
+//
+// CTEPagedCode();
+//
+/*++
+Routine Description:
+
+ This macro is used in NT to check if the Irql is above zero. All
+ coded that is pageable has this macro call to catch any code that might
+ be marked as pageable when in fact it isn't.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ NONE
+--*/
+#ifndef VXD
+#define CTEPagedCode() PAGED_CODE()
+#else
+#define CTEPagedCode()
+#ifdef CHICAGO
+#ifdef DEBUG
+#undef CTEPagedCode
+#define CTEPagedCode() _Debug_Flags_Service(DFS_TEST_REENTER+DFS_TEST_BLOCK)
+#endif
+#endif
+#endif
+
+
+//----------------------------------------------------------------------------
+//
+// CTEMakePageable(Page,Routine);
+//
+/*++
+Routine Description:
+
+ This macro is used in NT to activate teh alloc_text pragma, to put
+ a procedure in the pageable code segment.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ NONE
+--*/
+#define CTEMakePageable( _Page, _Routine ) \
+ alloc_text(_Page,_Routine)
+
+#ifdef CHICAGO
+#define ALLOC_PRAGMA
+#define INIT _ITEXT
+// #define PAGE _PTEXT "vmm.h" has a macro for this. We override it later.
+#endif // CHICAGO
+
+
+//----------------------------------------------------------------------------
+//
+// NTSetCancelRoutine(pIrp,Routine);
+//
+/*++
+Routine Description:
+
+ This macro removes the call to set the cancel routine for an irp from the
+ VXD environment.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ NONE
+--*/
+#ifdef VXD
+#define NTSetCancelRoutine(_pIrp,_CancelRoutine,_pDeviceContext) (0)
+#define NTCheckSetCancelRoutine(_pIrp,_CancelRoutine,_pDeviceContext) (0)
+#define NTClearContextCancel(pWiContext) (0)
+#endif
+
+//----------------------------------------------------------------------------
+//
+// NbtLogEvent(LogEvent,status)
+//
+/*++
+Routine Description:
+
+ This macro removes the call to the log routine for the Vxd environment
+
+
+Arguments:
+
+ none
+
+Return Value:
+
+ NONE
+--*/
+#ifdef VXD
+#define NbtLogEvent(LogEvent,status)
+#endif
+
+//----------------------------------------------------------------------------
+//
+// CTEGetTimeout(_pTimeout);
+//
+/*++
+Routine Description:
+
+ This macro gets the timeout value for a connect attempt
+ VXD environment.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ NONE
+--*/
+#ifndef VXD
+#define CTEGetTimeout(pTimeout,pRetTime) \
+{ \
+ LARGE_INTEGER _Timeout; \
+ ULONG Remainder; \
+ _Timeout.QuadPart = -(((PLARGE_INTEGER)pTimeout)->QuadPart); \
+ _Timeout = RtlExtendedLargeIntegerDivide(_Timeout,MILLISEC_TO_100NS,&Remainder);\
+ *pRetTime = (ULONG)_Timeout.LowPart; \
+}
+#else
+//
+// VXD timeout is a pointer to a ULONG
+//
+#define CTEGetTimeout(_pTimeout, pRet ) (*pRet = ((ULONG) _pTimeout ? *((PULONG)_pTimeout) : 0 ))
+#endif
+
+//----------------------------------------------------------------------------
+//
+// CTEAttachFsp()
+//
+/*++
+Routine Description:
+
+ This macro attaches a process to the File System Process to be sure
+ that handles are created and released in the same process
+
+Arguments:
+
+Return Value:
+
+ STATUS_SUCCESS if successful, error code otherwise
+
+--*/
+#ifndef VXD
+#define CTEAttachFsp(_pAttached) \
+{ \
+ if (PsGetCurrentProcess() != NbtFspProcess) \
+ { \
+ KeAttachProcess(&NbtFspProcess->Pcb); \
+ *_pAttached = TRUE; \
+ } \
+}
+#else
+#define CTEAttachFsp( _pAttached )
+#endif
+
+//----------------------------------------------------------------------------
+//
+// CTEAttachFsp()
+//
+/*++
+Routine Description:
+
+ This macro attaches a process to the File System Process to be sure
+ that handles are created and released in the same process
+
+Arguments:
+
+Return Value:
+
+ STATUS_SUCCESS if successful, error code otherwise
+
+--*/
+#ifndef VXD
+#define CTEDetachFsp(Attached) \
+{ \
+ if (Attached) \
+ { \
+ KeDetachProcess(); \
+ } \
+}
+#else
+#define CTEDetachFsp( Attached )
+#endif
+//----------------------------------------------------------------------------
+//
+// CTEResetIrpPending(PIRP pIrp)
+//
+/*++
+Routine Description:
+
+ This macro resets the irp pending bit in an irp.
+
+Arguments:
+
+Return Value:
+
+ STATUS_SUCCESS if successful, error code otherwise
+
+--*/
+#ifndef VXD
+#define CTEResetIrpPending(pIrp) \
+{ \
+ PIO_STACK_LOCATION pIrpsp; \
+ pIrpsp = IoGetCurrentIrpStackLocation(pIrp);\
+ pIrpsp->Control &= ~SL_PENDING_RETURNED; \
+}
+#else
+#define CTEResetIrpPending( a )
+#endif
+
+//----------------------------------------------------------------------------
+//
+// ADD_TO_LIST(pListHead,pTracker)
+//
+/*++
+Routine Description:
+
+ This macro adds a tracker from the "used Tracker List"
+
+Arguments:
+
+Return Value:
+
+ STATUS_SUCCESS if successful, error code otherwise
+
+--*/
+//#if DBG
+#define ADD_TO_LIST(pListHead,pLinkage) \
+{ \
+ CTELockHandle OldIrq; \
+ CTESpinLock(&NbtConfig,OldIrq); \
+ InsertTailList((pListHead),pLinkage); \
+ CTESpinFree(&NbtConfig,OldIrq); \
+}
+//#else
+//#define ADD_TO_LIST( a,b )
+//#endif
+//----------------------------------------------------------------------------
+//
+// REMOVE_FROM_LIST(pLinkage)
+//
+/*++
+Routine Description:
+
+ This macro removes a tracker from the "used Tracker List"
+
+Arguments:
+
+Return Value:
+
+ STATUS_SUCCESS if successful, error code otherwise
+
+--*/
+//#if DBG
+#define REMOVE_FROM_LIST(pLinkage) \
+{ \
+ CTELockHandle OldIrq; \
+ CTESpinLock(&NbtConfig,OldIrq); \
+ RemoveEntryList(pLinkage); \
+ CTESpinFree(&NbtConfig,OldIrq); \
+}
+//#else
+//#define REMOVE_FROM_LIST( a )
+//#endif
+//----------------------------------------------------------------------------
+//
+// CTESaveClientSecurity(pClientEle)
+//
+/*++
+Routine Description:
+
+ This macro saves the client thread security context so that it can be used
+ later to impersonate the client when a remote lmhosts file is openned.
+
+Arguments:
+
+Return Value:
+
+
+--*/
+#ifndef VXD
+#define CTESaveClientSecurity(_pClientEle) \
+ /*SaveClientSecurity(_pClientEle)*/
+#else
+#define CTESaveClientSecurity(_pClientEle)
+#endif
+
+//----------------------------------------------------------------------------
+//
+// IMPERSONATE_CLIENT(pClientSecurity)
+//
+/*++
+Routine Description:
+
+ This macro sets an excutive worker thread to impersonate a client
+ thread so that remote lmhost files can be openned by that thread.
+
+Arguments:
+
+Return Value:
+
+
+--*/
+#ifndef VXD
+#define IMPERSONATE_CLIENT(_pClientSecurity) \
+ /*SeImpersonateClient((_pClientSecurity),NULL)*/
+#else
+#define IMPERSONATE_CLIENT(_pClientSecurity)
+#endif
+//----------------------------------------------------------------------------
+//
+// STOP_IMPERSONATE_CLIENT(pClientSecurity)
+//
+/*++
+Routine Description:
+
+ This macro sets an excutive worker thread NOT to impersonate a client.
+
+Arguments:
+
+Return Value:
+
+
+--*/
+#ifndef VXD
+#define STOP_IMPERSONATE_CLIENT(_pClientSecurity) \
+ /*NtSetInformationThread(PsGetCurrentThread(),ThreadImpersonationToken,NULL,sizeof(HANDLE))*/
+#else
+#define STOP_IMPERSONATE_CLIENT(_pClientSecurity)
+#endif
+
+//----------------------------------------------------------------------------
+//
+// DELETE_CLIENT_SECURITY(pTracker)
+//
+/*++
+Routine Description:
+
+ This macro deletes a client security.
+
+Arguments:
+
+Return Value:
+
+
+--*/
+#ifndef VXD
+#define DELETE_CLIENT_SECURITY(_pTracker) \
+ /* NtDeleteClientSecurity(_pTracker)*/
+#else
+#define DELETE_CLIENT_SECURITY(_pTracker)
+#endif
+
+
+#ifdef VXD // Taken from ntrtl.h (Vxd doesn't include NT Headers)
+
+// Doubly-linked list manipulation routines. Implemented as macros
+// but logically these are procedures.
+//
+
+//
+// VOID
+// InitializeListHead(
+// PLIST_ENTRY ListHead
+// );
+//
+
+#define InitializeListHead(ListHead) (\
+ (ListHead)->Flink = (ListHead)->Blink = (ListHead))
+
+//
+// BOOLEAN
+// IsListEmpty(
+// PLIST_ENTRY ListHead
+// );
+//
+
+#define IsListEmpty(ListHead) \
+ ((ListHead)->Flink == (ListHead))
+
+//
+// PLIST_ENTRY
+// RemoveHeadList(
+// PLIST_ENTRY ListHead
+// );
+//
+
+#define RemoveHeadList(ListHead) \
+ (ListHead)->Flink;\
+ {RemoveEntryList((ListHead)->Flink)}
+
+//
+// PLIST_ENTRY
+// RemoveTailList(
+// PLIST_ENTRY ListHead
+// );
+//
+
+#define RemoveTailList(ListHead) \
+ (ListHead)->Blink;\
+ {RemoveEntryList((ListHead)->Blink)}
+
+//
+// VOID
+// RemoveEntryList(
+// PLIST_ENTRY Entry
+// );
+//
+
+#define RemoveEntryList(Entry) {\
+ PLIST_ENTRY _EX_Blink;\
+ PLIST_ENTRY _EX_Flink;\
+ _EX_Flink = (Entry)->Flink;\
+ _EX_Blink = (Entry)->Blink;\
+ _EX_Blink->Flink = _EX_Flink;\
+ _EX_Flink->Blink = _EX_Blink;\
+ }
+
+//
+// VOID
+// InsertTailList(
+// PLIST_ENTRY ListHead,
+// PLIST_ENTRY Entry
+// );
+//
+
+#define InsertTailList(ListHead,Entry) {\
+ PLIST_ENTRY _EX_Blink;\
+ PLIST_ENTRY _EX_ListHead;\
+ _EX_ListHead = (ListHead);\
+ _EX_Blink = _EX_ListHead->Blink;\
+ (Entry)->Flink = _EX_ListHead;\
+ (Entry)->Blink = _EX_Blink;\
+ _EX_Blink->Flink = (Entry);\
+ _EX_ListHead->Blink = (Entry);\
+ }
+
+//
+// VOID
+// InsertHeadList(
+// PLIST_ENTRY ListHead,
+// PLIST_ENTRY Entry
+// );
+//
+
+#define InsertHeadList(ListHead,Entry) {\
+ PLIST_ENTRY _EX_Flink;\
+ PLIST_ENTRY _EX_ListHead;\
+ _EX_ListHead = (ListHead);\
+ _EX_Flink = _EX_ListHead->Flink;\
+ (Entry)->Flink = _EX_Flink;\
+ (Entry)->Blink = _EX_ListHead;\
+ _EX_Flink->Blink = (Entry);\
+ _EX_ListHead->Flink = (Entry);\
+ }
+#endif // VXD
+
+
+#endif // _CTEMACRO_H_
diff --git a/private/ntos/nbt/inc/debug.h b/private/ntos/nbt/inc/debug.h
new file mode 100644
index 000000000..c4b99719d
--- /dev/null
+++ b/private/ntos/nbt/inc/debug.h
@@ -0,0 +1,70 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Debug.h
+
+Abstract:
+
+ This file contains debug printing constants for NBT.
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#ifndef _DEBUGNBT_H
+#define _DEBUGNBT_H
+
+//
+// Debug support.. this macro defines a check on a global flag that
+// selectively enables and disables debugging in different parts of NBT
+// NbtDebug is a global ULONG declared in driver.c
+//
+#if DBG
+extern ULONG NbtDebug;
+#endif // DBG
+
+#if DBG
+#define IF_DBG(flags) if(NbtDebug & flags)
+
+#define NBT_DEBUG_REGISTRY 0x00000001 // registry.c
+#define NBT_DEBUG_DRIVER 0x00000002 // driver.c
+#define NBT_DEBUG_NTUTIL 0x00000004 // ntutil.c
+#define NBT_DEBUG_TDIADDR 0x00000008 // tdiaddr.c
+#define NBT_DEBUG_TDICNCT 0x00000010 // tidaddr.c
+#define NBT_DEBUG_TDIHNDLR 0x00000020 // tdihndlr.c
+#define NBT_DEBUG_NAME 0x00000040 // name.c
+#define NBT_DEBUG_NTISOL 0x00000080 // ntisol.c
+#define NBT_DEBUG_NBTUTILS 0x00000100 // nbtutils.c
+#define NBT_DEBUG_NAMESRV 0x00000200 // namesrv.c
+#define NBT_DEBUG_HNDLRS 0x00000400 // hndlrs.c
+#define NBT_DEBUG_PROXY 0x00000800 // proxy.c
+#define NBT_DEBUG_HASHTBL 0x00001000 // hashtbl.c
+#define NBT_DEBUG_UDPSEND 0x00002000 // udpsend.c
+#define NBT_DEBUG_TDIOUT 0x00004000 // tdiout.c
+#define NBT_DEBUG_SEND 0x00008000 // sends
+#define NBT_DEBUG_RCV 0x00010000 // rcvs
+#define NBT_DEBUG_RCVIRP 0x00020000 // rcv irp processing
+#define NBT_DEBUG_INDICATEBUFF 0x00040000 // tdihndlrs.c indicate buffer
+#define NBT_DEBUG_MEMFREE 0x00080000 // memory alloc/free
+#define NBT_DEBUG_REF 0x00100000 // reference counts
+#define NBT_DEBUG_DISCONNECT 0x00200000 // Disconnects
+#define NBT_DEBUG_FILLIRP 0x00400000 // Filling the Irp(Rcv)
+#define NBT_DEBUG_LMHOST 0x00800000 // Lmhost file stuff
+#define NBT_DEBUG_REFRESH 0x01000000 // refresh logic
+#define NBT_DEBUG_FASTPATH 0x02000000 // Rcv code - fast path
+#define NBT_DEBUG_WINS 0x04000000 // Wins Interface debug
+#ifdef _PNP_POWER
+#define NBT_DEBUG_PNP_POWER 0x08000000 // NT PNP debugging
+#endif // _PNP_POWER
+#define NBT_DEBUG_NETBIOS_EX 0x10000000 // NETBIOS_EX address type debugging
+#else
+#define IF_DBG(flags)
+#endif
+#endif
diff --git a/private/ntos/nbt/inc/hosts.h b/private/ntos/nbt/inc/hosts.h
new file mode 100644
index 000000000..1ebf4755e
--- /dev/null
+++ b/private/ntos/nbt/inc/hosts.h
@@ -0,0 +1,279 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ lmhosts.h
+
+Abstract:
+
+ This is the header file for the lmhosts facility of the nbt driver.
+
+Author:
+
+ Eric Chin (ericc) April 28, 1992
+
+Revision History:
+
+--*/
+#ifndef _LMHOSTS_H_
+#define _LMHOSTS_H_
+
+
+
+//
+// Configuration Defaults
+//
+// Only the first MAX_PARSE_BYTES of each line in the lmhosts file is
+// examined.
+//
+
+#define DATABASEPATH "\\SystemRoot\\nt\\system32\\drivers\\etc"
+
+#define LMHOSTSFILE "lmhosts" // name of lmhosts file
+
+#define MAX_FILE_IO_THREADS 1 // threads to read
+ // lmhosts file
+#ifdef VXD
+#define MAX_PRELOAD 100 // max cache entries
+ // to preload
+#else
+#define MAX_PRELOAD 1000 // max cache entries
+ // to preload
+#endif
+
+#define SPECIAL_GROUP_SUFFIX 0x1C // for netlogon and
+ // the browser
+#define SPECIAL_BROWSER_SUFFIX 0x1D // for the browser
+#define MAX_MEMBERS_INTERNET_GROUP 50 // max size of internet group
+
+//
+// Reserved Keywords in the lmhosts File
+//
+#define BEG_ALT_TOKEN "#BEGIN_ALTERNATE" // alternate block
+#define DOMAIN_TOKEN "#DOM:" // specifies LM domain
+#define END_ALT_TOKEN "#END_ALTERNATE" // alternate block
+#define INCLUDE_TOKEN "#INCLUDE" // include a file
+#define PRELOAD_TOKEN "#PRE" // preload this entry
+#define NOFNR_TOKEN "#NOFNR" // no find name request
+
+
+//
+// Macro Definitions
+//
+
+//#define min(x, y) ((x) < (y) ? (x) : (y))
+
+
+
+//
+// Public Definitions
+//
+//
+// For each file that is opened, a LM_FILE object is created.
+//
+typedef struct _LM_FILE
+{
+#ifndef VXD
+ KSPIN_LOCK f_lock; // protects this object
+ LONG f_refcount; // current no of references
+#endif
+
+ HANDLE f_handle; // handle from ZwOpenFile()
+ LONG f_lineno; // current line number
+
+#ifndef VXD
+ LARGE_INTEGER f_fileOffset; // current offset into file
+
+ PUCHAR f_current; // buffer position to read
+ PUCHAR f_limit; // last byte + 1 of buffer
+ PUCHAR f_buffer; // start of buffer
+#else
+ PUCHAR f_linebuffer; // line buffer
+ PUCHAR f_buffer; // file buffer
+ BOOL f_EOF ; // TRUE if EOF
+ ULONG f_CurPos ; // Current Pos. in File Buffer
+ ULONG f_EndOfData ; // Last valid data in File Buffer
+ PUCHAR f_BackUp; // copy here In case of #INCLUDE
+#endif
+
+} LM_FILE, *PLM_FILE;
+
+
+//
+// The LM_IPADDRESS_LIST object contains pertinent information about a
+// group of ip addresses.
+//
+//
+typedef struct _LM_IPADDRESS_LIST
+{
+
+ KSPIN_LOCK i_rcntlock; // protects i_refcount
+ LONG i_refcount; // current no of references
+ KSPIN_LOCK i_lock; // only when adding to i_addrs[]
+ int i_maxaddrs; // max capacity of i_addrs[]
+ int i_numaddrs; // current no of ip addresses
+ unsigned long i_addrs[1]; // the array of ip addresses
+
+} LM_IPADDRESS_LIST, *PLM_IPADDRESS_LIST;
+
+
+//
+// An LM_PARSE_FUNCTION may be called recursively to handle #INCLUDE
+// directives in an lmhosts file.
+//
+//
+typedef unsigned long (* LM_PARSE_FUNCTION) (
+ IN PUCHAR path, // file to parse
+ IN PUCHAR target OPTIONAL, // NetBIOS name
+ IN BOOLEAN recurse, // process #INCLUDE's ?
+ OUT BOOLEAN *NoFindName // do not do find name
+);
+
+
+//
+// The LM_WORK_ITEM object is the interface between lm_lookup() and
+// LmFindName().
+//
+//
+typedef struct _LM_WORK_ITEM
+{ // work for io thread(s)
+
+ LIST_ENTRY w_list; // links to other items
+// mblk_t *w_mp; // STREAMS buffer
+
+} LM_WORK_ITEM, *PLM_WORK_ITEM;
+
+
+
+//
+// Private Function Prototypes
+//
+int
+LmAddToDomAddrList (
+ IN PUCHAR name,
+ IN unsigned long inaddr
+ );
+
+NTSTATUS
+LmCloseFile (
+ IN PLM_FILE handle
+ );
+
+NTSTATUS
+LmCreateThreads (
+ IN int nthreads
+ );
+
+NTSTATUS
+LmDeleteAllDomAddrLists (
+ VOID
+ );
+
+VOID
+LmDerefDomAddrList(
+ PLM_IPADDRESS_LIST arrayp
+ );
+
+char *
+LmExpandName (
+ OUT PUCHAR dest,
+ IN PUCHAR source,
+ IN UCHAR last
+ );
+
+PUCHAR
+LmFgets (
+ IN PLM_FILE pfile,
+ OUT int *nbytes
+ );
+
+NTSTATUS
+LmFindName (
+ VOID
+ );
+
+PLM_IPADDRESS_LIST
+LmGetDomAddrList (
+ PUCHAR name
+ );
+
+unsigned long
+LmGetIpAddr (
+ IN PUCHAR path,
+ IN PUCHAR target,
+ IN BOOLEAN recurse,
+ OUT BOOLEAN *NoFindName
+ );
+
+NTSTATUS
+LmGetFullPath (
+ IN PUCHAR target,
+ OUT PUCHAR *path
+ );
+
+unsigned long
+LmInclude(
+ IN PUCHAR file,
+ IN LM_PARSE_FUNCTION function,
+ IN PUCHAR argument,
+ OUT BOOLEAN *NoFindName
+ );
+
+NTSTATUS
+LmInitDomAddrLists (
+ VOID
+ );
+
+VOID
+LmLogOpenError (
+ IN PUCHAR path,
+ IN NTSTATUS unused
+ );
+
+VOID
+LmLogSyntaxError (
+ IN LONG lineno
+ );
+
+PLM_FILE
+LmOpenFile (
+ IN PUCHAR path
+ );
+
+int
+LmPreloadEntry (
+ IN PUCHAR name,
+ IN unsigned long inaddr,
+ IN unsigned int NoFNR
+ );
+
+BOOLEAN
+LmPutCacheEntry (
+// IN mblk_t *mp,
+ IN unsigned char *name,
+ IN unsigned long inaddr,
+ IN unsigned int ttl,
+ IN LONG nb_flags,
+ IN unsigned int NoFNR
+ );
+
+NTSTATUS
+LmTerminateThreads(
+ VOID
+ );
+
+//
+// Functions Imported from ..\common
+//
+extern unsigned long
+inet_addr(
+ IN char *cp
+ );
+
+
+
+
+#endif // _LMHOSTS_H_
+
diff --git a/private/ntos/nbt/inc/nbtinfo.h b/private/ntos/nbt/inc/nbtinfo.h
new file mode 100644
index 000000000..93b5805fa
--- /dev/null
+++ b/private/ntos/nbt/inc/nbtinfo.h
@@ -0,0 +1,28 @@
+/**********************************************************************/
+/** Microsoft Windows/NT **/
+/** Copyright(c) Microsoft Corp., 1993 **/
+/**********************************************************************/
+
+/*
+ NbtInfo.h
+
+ This file contains the NBT Info APIs
+
+
+
+ FILE HISTORY:
+ Johnl 13-Dec-1993 Created
+
+*/
+
+#ifndef _NBTINFO_H_
+#define _NBTINFO_H_
+
+VOID AddrChngNotification( PVOID Context,
+ ULONG OldIpAddress,
+ ULONG NewIpAddress,
+ ULONG NewMask ) ;
+
+
+
+#endif //!_NBTINFO_H_
diff --git a/private/ntos/nbt/inc/nbtnt.h b/private/ntos/nbt/inc/nbtnt.h
new file mode 100644
index 000000000..e708aac52
--- /dev/null
+++ b/private/ntos/nbt/inc/nbtnt.h
@@ -0,0 +1,272 @@
+//
+// NBTNT.H
+//
+// This file contains common header definitions for NBT in the NT
+// environment
+//
+//
+
+#ifndef _NBT_H
+#define _NBT_H
+
+#ifndef VXD
+#include <ntos.h>
+#include <status.h>
+#include <ntstatus.h>
+#include <tdikrnl.h>
+#include <tdi.h>
+#include <sockets/netinet/in.h> // htons, ntohs
+#include <windef.h>
+#include <stdio.h>
+#include <nb30.h>
+#include <zwapi.h>
+
+#else
+
+#include <oscfgnbt.h>
+#include <cxport.h>
+#define __int64 double
+#include <windef.h>
+#include <nb30.h>
+#include <sockets/netinet/in.h> // htons, ntohs
+
+//
+// These definitions work around NTisms found in various difficult to change
+// places.
+//
+typedef ULONG NTSTATUS ;
+typedef PNCB PIRP ;
+typedef PVOID PDEVICE_OBJECT ;
+
+#include <ctemacro.h>
+#include <tdi.h>
+
+//
+// These are needed because we include windef.h rather then
+// ntddk.h, which end up not being defined
+//
+#define STATUS_NETWORK_NAME_DELETED ((NTSTATUS)0xC00000CAL)
+#define STATUS_INVALID_BUFFER_SIZE ((NTSTATUS)0xC0000206L)
+#define STATUS_CONNECTION_DISCONNECTED ((NTSTATUS)0xC000020CL)
+#define STATUS_CANCELLED ((NTSTATUS)0xC0000120L)
+#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
+
+#define STATUS_TOO_MANY_COMMANDS ((NTSTATUS)0xC00000C1L)
+#define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS)0xC0000035L)
+#define STATUS_SHARING_VIOLATION ((NTSTATUS)0xC0000043L)
+#define STATUS_DUPLICATE_NAME ((NTSTATUS)0xC00000BDL)
+#define STATUS_BAD_NETWORK_PATH ((NTSTATUS)0xC00000BEL)
+#define STATUS_REMOTE_NOT_LISTENING ((NTSTATUS)0xC00000BCL)
+#define STATUS_CONNECTION_REFUSED ((NTSTATUS)0xC0000236L)
+#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL)
+#define STATUS_UNEXPECTED_NETWORK_ERROR ((NTSTATUS)0xC00000C4L)
+#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
+
+#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008L)
+#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L)
+
+#define STATUS_INVALID_PARAMETER_6 ((NTSTATUS)0xC00000F4L)
+
+//
+// The following functions are used by NBT. They are defined in the NT kernel
+// TDI stuff which we are trying to avoid.
+//
+
+typedef
+NTSTATUS
+(*PTDI_IND_CONNECT)(
+ IN PVOID TdiEventContext,
+ IN int RemoteAddressLength,
+ IN PVOID RemoteAddress,
+ IN int UserDataLength,
+ IN PVOID UserData,
+ IN int OptionsLength,
+ IN PVOID Options,
+ OUT CONNECTION_CONTEXT *ConnectionContext
+ )
+ ;
+
+NTSTATUS
+TdiDefaultConnectHandler (
+ IN PVOID TdiEventContext,
+ IN int RemoteAddressLength,
+ IN PVOID RemoteAddress,
+ IN int UserDataLength,
+ IN PVOID UserData,
+ IN int OptionsLength,
+ IN PVOID Options,
+ OUT CONNECTION_CONTEXT *ConnectionContext
+ );
+
+//
+// Disconnection indication prototype. This is invoked when a connection is
+// being disconnected for a reason other than the user requesting it. Note that
+// this is a change from TDI V1, which indicated only when the remote caused
+// a disconnection. Any non-directed disconnection will cause this indication.
+//
+
+typedef
+NTSTATUS
+(*PTDI_IND_DISCONNECT)(
+ IN PVOID TdiEventContext,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN int DisconnectDataLength,
+ IN PVOID DisconnectData,
+ IN int DisconnectInformationLength,
+ IN PVOID DisconnectInformation,
+ IN ULONG DisconnectFlags
+ );
+
+NTSTATUS
+TdiDefaultDisconnectHandler (
+ IN PVOID TdiEventContext,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN int DisconnectDataLength,
+ IN PVOID DisconnectData,
+ IN int DisconnectInformationLength,
+ IN PVOID DisconnectInformation,
+ IN ULONG DisconnectFlags
+ );
+
+//
+// A protocol error has occurred when this indication happens. This indication
+// occurs only for errors of the worst type; the address this indication is
+// delivered to is no longer usable for protocol-related operations, and
+// should not be used for operations henceforth. All connections associated
+// it are invalid.
+// For NetBIOS-type providers, this indication is also delivered when a name
+// in conflict or duplicate name occurs.
+//
+
+typedef
+NTSTATUS
+(*PTDI_IND_ERROR)(
+ IN PVOID TdiEventContext, // the endpoint's file object.
+ IN NTSTATUS Status // status code indicating error type.
+ );
+
+NTSTATUS
+TdiDefaultErrorHandler (
+ IN PVOID TdiEventContext, // the endpoint's file object.
+ IN NTSTATUS Status // status code indicating error type.
+ );
+
+//
+// TDI_IND_RECEIVE indication handler definition. This client routine is
+// called by the transport provider when a connection-oriented TSDU is received
+// that should be presented to the client.
+//
+
+typedef
+NTSTATUS
+(*PTDI_IND_RECEIVE)(
+ 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.
+ );
+
+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.
+ );
+
+//
+// TDI_IND_RECEIVE_DATAGRAM indication handler definition. This client routine
+// is called by the transport provider when a connectionless TSDU is received
+// that should be presented to the client.
+//
+
+typedef
+NTSTATUS
+(*PTDI_IND_RECEIVE_DATAGRAM)(
+ IN PVOID TdiEventContext, // the event context
+ IN int SourceAddressLength, // length of the originator of the datagram
+ IN PVOID SourceAddress, // string describing the originator of the datagram
+ IN int OptionsLength, // options for the receive
+ IN PVOID Options, //
+ 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.
+ );
+
+NTSTATUS
+TdiDefaultRcvDatagramHandler (
+ IN PVOID TdiEventContext, // the event context
+ IN int SourceAddressLength, // length of the originator of the datagram
+ IN PVOID SourceAddress, // string describing the originator of the datagram
+ IN int OptionsLength, // options for the receive
+ IN PVOID Options, //
+ 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.
+ );
+
+//
+// This indication is delivered if expedited data is received on the connection.
+// This will only occur in providers that support expedited data.
+//
+
+typedef
+NTSTATUS
+(*PTDI_IND_RECEIVE_EXPEDITED)(
+ 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.
+ );
+
+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.
+ );
+
+//
+// This indication is delivered if there is room for a send in the buffer of
+// a buffering protocol.
+//
+
+typedef
+NTSTATUS
+(*PTDI_IND_SEND_POSSIBLE)(
+ IN PVOID TdiEventContext,
+ IN PVOID ConnectionContext,
+ IN ULONG BytesAvailable);
+
+NTSTATUS
+TdiDefaultSendPossibleHandler (
+ IN PVOID TdiEventContext,
+ IN PVOID ConnectionContext,
+ IN ULONG BytesAvailable);
+
+#endif //VXD
+
+#define FILE_DEVICE_NBT 0x32
+#endif
+
diff --git a/private/ntos/nbt/inc/nbtprocs.h b/private/ntos/nbt/inc/nbtprocs.h
new file mode 100644
index 000000000..8f3d00291
--- /dev/null
+++ b/private/ntos/nbt/inc/nbtprocs.h
@@ -0,0 +1,1451 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Nbtprocs.h
+
+Abstract:
+
+ This file contains the OS independent function prototypes.
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+ Johnl 05-Apr-1993 Hacked on to support VXD
+
+--*/
+
+
+#ifndef _NBTPROCS_H_
+#define _NBTPROCS_H_
+
+#include "types.h"
+
+#ifndef VXD
+ #include <ntprocs.h>
+#else
+ #include <vxdprocs.h>
+#endif
+
+//---------------------------------------------------------------------
+// FROM NAMESRV.C
+//
+tNAMEADDR *
+FindName(
+ enum eNbtLocation Location,
+ PCHAR pName,
+ PCHAR pScope,
+ USHORT *pRetNameType
+ );
+
+NTSTATUS
+NbtRegisterName(
+ IN enum eNbtLocation Location,
+ IN ULONG IpAddress,
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN PVOID pClientContext,
+ IN PVOID pClientCompletion,
+ IN USHORT uAddressType,
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+NTSTATUS
+ReleaseNameOnNet(
+ tNAMEADDR *pNameAddr,
+ PCHAR pScope,
+ PVOID pClientContext,
+ PVOID pClientCompletion,
+ ULONG NodeType,
+ tDEVICECONTEXT *pDeviceContext
+ );
+
+VOID
+NameReleaseDone(
+ PVOID pContext,
+ NTSTATUS status
+ );
+
+VOID
+NameReleaseDoneOnDynIf(
+ PVOID pContext,
+ NTSTATUS status
+ );
+
+NTSTATUS
+RegOrQueryFromNet(
+ IN BOOL fReg,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN PCHAR pName,
+ IN PUCHAR pScope
+ );
+
+NTSTATUS
+QueryNameOnNet(
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN ULONG IpAddress,
+ IN USHORT uType,
+ IN PVOID pClientContext,
+ IN PVOID pClientCompletion,
+ IN ULONG NodeType,
+ IN tNAMEADDR *pNameAddrIn,
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT tDGRAM_SEND_TRACKING **ppTracker,
+ IN CTELockHandle *pJointLockOldIrq
+ );
+
+VOID
+CompleteClientReq(
+ COMPLETIONCLIENT pClientCompletion,
+ tDGRAM_SEND_TRACKING *pTracker,
+ NTSTATUS status
+ );
+
+ VOID
+DereferenceTracker(
+ IN tDGRAM_SEND_TRACKING *pTracker
+ );
+
+VOID
+DereferenceTrackerNoLock(
+ IN tDGRAM_SEND_TRACKING *pTracker
+ );
+
+VOID
+NodeStatusCompletion(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+
+VOID
+RefreshTimeout(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+
+VOID
+RemoteHashTimeout(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+
+VOID
+SessionKeepAliveTimeout(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+
+VOID
+IncrementNameStats(
+ IN ULONG StatType,
+ IN BOOLEAN IsNameServer
+ );
+
+VOID
+SaveBcastNameResolved(
+ IN PUCHAR pName
+ );
+
+//---------------------------------------------------------------------
+// FROM NAME.C
+
+VOID
+FreeRcvBuffers(
+ tCONNECTELE *pConnEle,
+ CTELockHandle *pOldIrq
+ );
+VOID
+LockedDereferenceName(
+ IN tNAMEADDR *pNameAddr
+ );
+
+NTSTATUS
+NbtRegisterCompletion(
+ IN tCLIENTELE *pClientEle,
+ IN NTSTATUS Status);
+
+NTSTATUS
+NbtOpenAddress(
+ IN TDI_REQUEST *pRequest,
+ IN TA_ADDRESS UNALIGNED *pTaAddress,
+ IN ULONG IpAddress,
+ IN PVOID pSecurityDescriptor,
+ IN tDEVICECONTEXT *pContext,
+ IN PVOID pIrp);
+
+NTSTATUS
+NbtOpenConnection(
+ IN TDI_REQUEST *pRequest,
+ IN CONNECTION_CONTEXT pConnectionContext,
+ IN tDEVICECONTEXT *pContext);
+
+NTSTATUS
+NbtOpenAndAssocConnection(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+NTSTATUS
+NbtAssociateAddress(
+ IN TDI_REQUEST *pRequest,
+ IN tCLIENTELE *pClientEle,
+ IN PVOID pIrp);
+
+NTSTATUS
+NbtDisassociateAddress(
+ IN TDI_REQUEST *pRequest
+ );
+
+NTSTATUS
+NbtCloseAddress(
+ IN TDI_REQUEST *pRequest,
+ OUT TDI_REQUEST_STATUS *pRequestStatus,
+ IN tDEVICECONTEXT *pContext,
+ IN PVOID pIrp);
+
+NTSTATUS
+NbtCleanUpAddress(
+ IN tCLIENTELE *pClientEle,
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+NTSTATUS
+NbtCloseConnection(
+ IN TDI_REQUEST *pRequest,
+ OUT TDI_REQUEST_STATUS *pRequestStatus,
+ IN tDEVICECONTEXT *pContext,
+ IN PVOID pIrp);
+
+NTSTATUS
+NbtCleanUpConnection(
+ IN tCONNECTELE *pConnEle,
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+VOID
+RelistConnection(
+ IN tCONNECTELE *pConnEle
+ );
+
+NTSTATUS
+CleanupConnectingState(
+ IN tCONNECTELE *pConnEle,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN CTELockHandle *OldIrq,
+ IN CTELockHandle *OldIrq2
+ );
+
+VOID
+ReConnect(
+ IN PVOID Context
+ );
+
+NTSTATUS
+NbtConnect(
+ IN TDI_REQUEST *pRequest,
+ IN PVOID pTimeout,
+ IN PTDI_CONNECTION_INFORMATION pCallInfo,
+ IN PTDI_CONNECTION_INFORMATION pReturnInfo,
+ IN PIRP pIrp
+ );
+
+VOID
+SessionSetupContinue(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ );
+
+VOID
+SessionTimedOut(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+
+VOID
+QueueCleanup(
+ IN tCONNECTELE *pConnEle
+ );
+
+NTSTATUS
+NbtDisconnect(
+ IN TDI_REQUEST *pRequest,
+ IN PVOID pTimeout,
+ IN ULONG Flags,
+ IN PTDI_CONNECTION_INFORMATION pCallInfo,
+ IN PTDI_CONNECTION_INFORMATION pReturnInfo,
+ IN PIRP pIrp);
+
+NTSTATUS
+NbtSend(
+ IN TDI_REQUEST *pRequest,
+ IN USHORT Flags,
+ IN ULONG SendLength,
+ OUT LONG *pSentLength,
+ IN PVOID *pBuffer,
+ IN tDEVICECONTEXT *pContext,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+NbtSendDatagram(
+ IN TDI_REQUEST *pRequest,
+ IN PTDI_CONNECTION_INFORMATION pSendInfo,
+ IN LONG SendLength,
+ IN LONG *pSentLength,
+ IN PVOID pBuffer,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+SendDgram(
+ IN tNAMEADDR *pNameAddr,
+ IN tDGRAM_SEND_TRACKING *pTracker
+ );
+NTSTATUS
+
+BuildSendDgramHdr(
+ IN ULONG SendLength,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PCHAR pSourceName,
+ IN PCHAR pDestinationName,
+ IN PVOID pBuffer,
+ OUT tDGRAMHDR **ppDgramHdr,
+ OUT tDGRAM_SEND_TRACKING **ppTracker
+ );
+
+VOID
+NodeStatusDone(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ );
+
+NTSTATUS
+NbtSendNodeStatus(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PCHAR pName,
+ IN PIRP pIrp,
+ IN PULONG pIpAddrsList,
+ IN PVOID ClientContext,
+ IN PVOID CompletionRoutine
+ );
+
+NTSTATUS
+NbtQueryFindName(
+ IN PTDI_CONNECTION_INFORMATION pInfo,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp,
+ IN BOOLEAN IsIoctl
+ );
+
+NTSTATUS
+CopyFindNameData(
+ IN tNAMEADDR *pNameAddr,
+ IN PIRP pIrp,
+ IN ULONG SrcAddress);
+
+NTSTATUS
+NbtListen(
+ IN TDI_REQUEST *pRequest,
+ IN ULONG Flags,
+ IN TDI_CONNECTION_INFORMATION *pRequestConnectInfo,
+ OUT TDI_CONNECTION_INFORMATION *pReturnConnectInfo,
+ IN PVOID pIrp);
+
+NTSTATUS
+NbtAccept(
+ IN TDI_REQUEST *pRequest,
+ IN TDI_CONNECTION_INFORMATION *pAcceptInfo,
+ OUT TDI_CONNECTION_INFORMATION *pReturnAcceptInfo,
+ IN PIRP pIrp);
+
+NTSTATUS
+NbtReceiveDatagram(
+ IN TDI_REQUEST *pRequest,
+ IN PTDI_CONNECTION_INFORMATION pReceiveInfo,
+ IN PTDI_CONNECTION_INFORMATION pReturnedInfo,
+ IN LONG ReceiveLength,
+ IN LONG *pReceivedLength,
+ IN PVOID pBuffer,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+NbtSetEventHandler(
+ tCLIENTELE *pClientEle,
+ int EventType,
+ PVOID pEventHandler,
+ PVOID pEventContext
+ );
+
+NTSTATUS
+NbtQueryAdapterStatus(
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT PVOID *ppAdapterStatus,
+ OUT PLONG pSize
+ );
+
+ NTSTATUS
+NbtQueryConnectionList(
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT PVOID *ppConnList,
+ IN OUT PLONG pSize
+ );
+
+NTSTATUS
+NbtResyncRemoteCache(
+ );
+
+ NTSTATUS
+NbtQueryBcastVsWins(
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT PVOID *ppBuffer,
+ IN OUT PLONG pSize
+ );
+
+NTSTATUS
+NbtNewDhcpAddress(
+ tDEVICECONTEXT *pDeviceContext,
+ ULONG IpAddress,
+ ULONG SubnetMask);
+
+VOID
+FreeTracker(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN ULONG Actions
+ );
+
+NTSTATUS
+DatagramDistribution(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN tNAMEADDR *pNameAddr
+ );
+
+VOID
+DereferenceIfNotInRcvHandler(
+ IN tCONNECTELE *pConnEle,
+ IN tLOWERCONNECTION *pLowerConn
+ );
+VOID
+DeleteAddressElement(
+ IN tADDRESSELE *pAddress
+ );
+
+VOID
+DeleteClientElement(
+ IN tCLIENTELE *pClientEle
+ );
+
+VOID
+NbtDereferenceLowerConnection(
+ IN tLOWERCONNECTION *pLowerConn
+ );
+
+VOID
+ReleaseNameCompletion(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo);
+
+NTSTATUS
+DisconnectLower(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG state,
+ IN ULONG Flags,
+ IN PVOID Timeout,
+ IN BOOLEAN Wait
+ );
+
+NTSTATUS
+NbtDereferenceConnection(
+ IN tCONNECTELE *pConnEle
+ );
+
+VOID
+NbtDereferenceName(
+ IN tNAMEADDR *pNameAddr
+ );
+
+NTSTATUS
+NbtDeleteLowerConn(
+ IN tLOWERCONNECTION *pLowerConn
+ );
+
+USHORT
+GetTransactId(
+ );
+
+USHORT
+GetTransactIdLocked(
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM TDICNCT.C
+//
+NTSTATUS
+NbtTdiOpenConnection (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+NTSTATUS
+NbtTdiAssociateConnection(
+ IN PFILE_OBJECT pFileObject,
+ IN HANDLE Handle
+ );
+
+NTSTATUS
+TdiOpenandAssocConnection(
+ IN tCONNECTELE *pConnEle,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN ULONG PortNumber
+ );
+
+NTSTATUS
+NbtTdiCloseConnection(
+ IN tLOWERCONNECTION *pLowerConn
+ );
+
+NTSTATUS
+NbtTdiCloseAddress(
+ IN tLOWERCONNECTION *pLowerConn
+ );
+
+
+//---------------------------------------------------------------------
+//
+// FROM TDIADDR.C
+//
+NTSTATUS
+NbtTdiOpenAddress (
+ OUT PHANDLE pFileHandle,
+ OUT PDEVICE_OBJECT *pDeviceObject,
+ OUT PFILE_OBJECT *pFileObject,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN USHORT PortNumber,
+ IN ULONG IpAddress,
+ IN ULONG Flags
+ );
+
+NTSTATUS
+CompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+NTSTATUS
+NbtTdiOpenControl (
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM NBTUTILS.C
+//
+
+void
+FreeList(
+ PLIST_ENTRY pHead,
+ PLIST_ENTRY pFreeQ);
+
+void
+NbtFreeAddressObj(
+ tADDRESSELE *pBlk);
+
+void
+NbtFreeClientObj(
+ tCLIENTELE *pBlk);
+
+void
+FreeConnectionObj(
+ tCONNECTELE *pBlk);
+
+tCLIENTELE *
+NbtAllocateClientBlock(tADDRESSELE *pAddrEle);
+
+NTSTATUS
+NbtAddPermanentName(
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+NTSTATUS
+NbtAddPermanentNameNotFound(
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+VOID
+NbtRemovePermanentName(
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+NTSTATUS
+ConvertDottedDecimalToUlong(
+ IN PUCHAR pInString,
+ OUT PULONG IpAddress);
+
+NTSTATUS
+NbtInitQ(
+ PLIST_ENTRY pListHead,
+ LONG iSizeBuffer,
+ LONG iNumBuffers);
+
+NTSTATUS
+NbtInitTrackerQ(
+ PLIST_ENTRY pListHead,
+ LONG iNumBuffers
+ );
+
+tDGRAM_SEND_TRACKING *
+NbtAllocTracker(
+ IN VOID
+ );
+
+NTSTATUS
+NbtGetBuffer(
+ PLIST_ENTRY pListHead,
+ PLIST_ENTRY *ppListEntry,
+ enum eBUFFER_TYPES eBuffType);
+
+NTSTATUS
+GetNetBiosNameFromTransportAddress(
+ IN PTA_NETBIOS_ADDRESS pTransAddr,
+ OUT PCHAR *pName,
+ OUT PULONG pNameLen,
+ OUT PULONG pNameType
+ );
+
+NTSTATUS
+ConvertToAscii(
+ IN PCHAR pNameHdr,
+ IN LONG NumBytes,
+ OUT PCHAR pName,
+ OUT PCHAR *pScope,
+ OUT PULONG pNameSize
+ );
+
+PCHAR
+ConvertToHalfAscii(
+ OUT PCHAR pDest,
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN ULONG ScopeSize
+ );
+
+ULONG
+Nbt_inet_addr(
+ IN PCHAR pName
+ );
+
+NTSTATUS
+BuildQueryResponse(
+ IN USHORT sNameSize,
+ IN tNAMEHDR *pNameHdr,
+ IN ULONG uTtl,
+ IN ULONG IpAddress,
+ OUT ULONG uNumBytes,
+ OUT PVOID pResponse,
+ IN PVOID pName,
+ IN USHORT NameType,
+ IN USHORT RetCode
+ );
+
+NTSTATUS
+GetTracker(
+ OUT tDGRAM_SEND_TRACKING **ppTracker);
+
+NTSTATUS
+GetIrp(
+ OUT PIRP *ppIrp);
+
+NTSTATUS
+NbtDereferenceAddress(
+ IN tADDRESSELE *pAddressEle
+ );
+
+NTSTATUS
+NbtDereferenceClient(
+ IN tCLIENTELE *pClientEle
+ );
+
+ULONG
+CountLocalNames(IN tNBTCONFIG *pNbtConfig
+ );
+
+ULONG
+CountUpperConnections(
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+NTSTATUS
+DisableInboundConnections(
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT PLIST_ENTRY pLowerConnFreeHead
+ );
+
+ULONG
+CloseLowerConnections(
+ IN PLIST_ENTRY pLowerConnFreeHead
+ );
+
+VOID
+MarkForCloseLowerConnections(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN CTELockHandle OldIrqJoint,
+ IN CTELockHandle OldIrqDevice
+ );
+
+NTSTATUS
+NbtInitConnQ(
+ PLIST_ENTRY pListHead,
+ int iSizeBuffer,
+ int iNumConnections,
+ tDEVICECONTEXT *pDeviceContext);
+
+NTSTATUS
+ReRegisterLocalNames(
+ );
+
+NTSTATUS
+LockedStopTimer(
+ tTIMERQENTRY **ppTimer);
+
+//---------------------------------------------------------------------
+//
+// FROM hndlrs.c
+//
+
+NTSTATUS
+RcvHandlrNotOs (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID UNALIGNED pTsdu,
+ OUT PVOID *RcvBuffer
+ );
+
+ NTSTATUS
+Inbound (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID UNALIGNED pTsdu,
+ OUT PVOID *RcvBuffer
+
+ );
+NTSTATUS
+Outbound (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID UNALIGNED pTsdu,
+ OUT PVOID *RcvBuffer
+ );
+NTSTATUS
+RejectAnyData(
+ IN PVOID ReceiveEventContext,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID UNALIGNED pTsdu,
+ OUT PVOID *ppIrp
+ );
+
+VOID
+RejectSession(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG StatusCode,
+ IN ULONG SessionStatus,
+ IN BOOLEAN SendNegativeSessionResponse
+ );
+
+VOID
+GetIrpIfNotCancelled(
+ IN tCONNECTELE *pConnEle,
+ OUT PIRP *ppIrp
+ );
+
+NTSTATUS
+FindSessionEndPoint(
+ IN VOID UNALIGNED *pTsdu,
+ IN PVOID ConnectionContext,
+ IN ULONG BytesIndicated,
+ OUT tCLIENTELE **ppClientEle,
+ OUT PVOID *ppRemoteAddress,
+ OUT PULONG pRemoteAddressLength
+ );
+
+VOID
+SessionRetry(
+ IN PVOID pContext,
+ IN PVOID pContext2,
+ IN tTIMERQENTRY *pTimerQEntry
+ );
+
+tCONNECTELE *
+SearchConnectionList(
+ IN tCLIENTELE *pClientEle,
+ IN PVOID pClientContext
+ );
+
+NTSTATUS
+ConnectHndlrNotOs (
+ IN PVOID pConnectionContext,
+ IN LONG RemoteAddressLength,
+ IN PVOID pRemoteAddress,
+ IN int UserDataLength,
+ IN PVOID UNALIGNED pUserData,
+ OUT CONNECTION_CONTEXT *ppConnectionId
+ );
+
+NTSTATUS
+DisconnectHndlrNotOs (
+ PVOID EventContext,
+ PVOID ConnectionContext,
+ ULONG DisconnectDataLength,
+ PVOID UNALIGNED pDisconnectData,
+ ULONG DisconnectInformationLength,
+ PVOID pDisconnectInformation,
+ ULONG DisconnectIndicators
+ );
+
+VOID
+CleanupAfterDisconnect(
+ IN PVOID pContext
+ );
+
+NTSTATUS
+DgramHndlrNotOs(
+ IN PVOID ReceiveEventContext,
+ IN ULONG SourceAddrLength,
+ IN PVOID pSourceAddr,
+ IN ULONG OptionsLength,
+ IN PVOID pOptions,
+ IN ULONG ReceiveDatagramFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG pBytesTaken,
+ IN PVOID UNALIGNED pTsdu,
+ OUT PVOID *ppRcvBuffer,
+ OUT tCLIENTLIST **ppAddressEle
+ );
+
+NTSTATUS
+NameSrvHndlrNotOs (
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameSrv,
+ IN ULONG uNumBytes,
+ IN BOOLEAN fBroadcast
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM proxy.c
+//
+
+NTSTATUS
+ReleaseResponseFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG NumBytes
+ );
+
+NTSTATUS
+ProxyQueryFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN USHORT OpCodeFlags
+ );
+
+NTSTATUS
+ProxyDoDgramDist(
+ IN tDGRAMHDR UNALIGNED *pDgram,
+ IN DWORD DgramLen,
+ IN tNAMEADDR *pNameAddr,
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+
+VOID
+ProxyTimerComplFn (
+ IN PVOID pContext,
+ IN PVOID pContext2,
+ IN tTIMERQENTRY *pTimerQEntry
+ );
+
+VOID
+ProxyRespond (
+ IN tQUERYRESP *pQuery,
+ IN PUCHAR pName,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN tNAMEHDR *pNameHdr,
+ IN ULONG lNameSize,
+ IN ULONG SrcAddress,
+ IN PTDI_ADDRESS_IP pAddressIp
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM hashtbl.c
+//
+NTSTATUS
+CreateHashTable(
+ tHASHTABLE **pHashTable,
+ LONG NumBuckets,
+ enum eNbtLocation LocalRemote
+ );
+
+NTSTATUS
+InitRemoteHashTable(
+ IN tNBTCONFIG *pConfig,
+ IN LONG NumBuckets,
+ IN LONG NumNames
+ );
+
+NTSTATUS
+AddNotFoundToHashTable(
+ IN tHASHTABLE *pHashTable,
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN ULONG IpAddress,
+ IN enum eNbtAddrType NameType,
+ OUT tNAMEADDR **ppNameAddress
+ );
+
+NTSTATUS
+AddRecordToHashTable(
+ IN tNAMEADDR *pNameAddr,
+ IN PCHAR pScope
+ );
+
+NTSTATUS
+AddToHashTable(
+ IN tHASHTABLE *pHashTable,
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN ULONG IpAddress,
+ IN enum eNbtAddrType NameType,
+ IN tNAMEADDR *pNameAddr,
+ OUT tNAMEADDR **ppNameAddress
+ );
+
+NTSTATUS
+DeleteFromHashTable(
+ tHASHTABLE *pHashTable,
+ PCHAR pName
+ );
+
+NTSTATUS
+ChgStateOfScopedNameInHashTable(
+ tHASHTABLE *pHashTable,
+ PCHAR pName,
+ PCHAR pScope,
+ DWORD NewState
+ );
+
+NTSTATUS
+FindInHashTable(
+ tHASHTABLE *pHashTable,
+ PCHAR pName,
+ PCHAR pScope,
+ tNAMEADDR **pNameAddress
+ );
+
+NTSTATUS
+FindNoScopeInHashTable(
+ tHASHTABLE *pHashTable,
+ PCHAR pName,
+ tNAMEADDR **pNameAddress
+ );
+
+NTSTATUS
+UpdateHashTable(
+ tHASHTABLE *pHashTable,
+ PCHAR pName,
+ PCHAR pScope,
+ ULONG IpAddress,
+ BOOLEAN bGroup,
+ tNAMEADDR **ppNameAddr
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM timer.c
+//
+
+NTSTATUS
+InitTimerQ(
+ IN int NumInQ);
+
+NTSTATUS
+InitQ(
+ IN int NumInQ,
+ IN tTIMERQ *pTimerQ,
+ IN USHORT uSize);
+
+VOID
+StopTimerAndCallCompletion(
+ IN tTIMERQENTRY *pTimer,
+ IN NTSTATUS status,
+ IN CTELockHandle OldIrq
+ );
+
+NTSTATUS
+InterlockedCallCompletion(
+ IN tTIMERQENTRY *pTimer,
+ IN NTSTATUS status
+ );
+
+NTSTATUS
+GetEntry(
+ IN PLIST_ENTRY pQHead,
+ IN USHORT uSize,
+ OUT PLIST_ENTRY *ppEntry);
+
+NTSTATUS
+LockedStartTimer(
+ IN ULONG DeltaTime,
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PVOID CompletionRoutine,
+ IN PVOID ContextClient,
+ IN PVOID CompletionClient,
+ IN USHORT Retries,
+ IN tNAMEADDR *pNameAddr,
+ IN BOOLEAN CrossLink
+ );
+
+NTSTATUS
+StartTimer(
+ IN ULONG DeltaTime,
+ IN PVOID Context,
+ IN PVOID Context2,
+ IN PVOID CompletionRoutine,
+ IN PVOID ContextClient,
+ IN PVOID CompletionClient,
+ IN USHORT Retries,
+ OUT tTIMERQENTRY **ppTimerEntry);
+
+NTSTATUS
+StopTimer(
+ IN tTIMERQENTRY *pTimerEntry,
+ OUT COMPLETIONCLIENT *pClient,
+ OUT PVOID *ppContext);
+
+
+//---------------------------------------------------------------------
+//
+// FROM udpsend.c
+//
+
+NTSTATUS
+UdpSendQueryNs(
+ PCHAR pName,
+ PCHAR pScope
+ );
+NTSTATUS
+UdpSendQueryBcast(
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN tDGRAM_SEND_TRACKING *pSentList
+ );
+NTSTATUS
+UdpSendRegistrationNs(
+ PCHAR pName,
+ PCHAR pScope
+ );
+
+NTSTATUS
+UdpSendNSBcast(
+ IN tNAMEADDR *pNameAddr,
+ IN PCHAR pScope,
+ IN tDGRAM_SEND_TRACKING *pSentList,
+ IN PVOID pCompletionRoutine,
+ IN PVOID pClientContext,
+ IN PVOID pClientCompletion,
+ IN ULONG Retries,
+ IN ULONG Timeout,
+ IN enum eNSTYPE eNsType,
+ IN BOOL SendFlag
+ );
+
+VOID
+NsDgramSendCompleted(
+ PVOID pContext,
+ NTSTATUS status,
+ ULONG lInfo
+ );
+
+VOID
+NameDgramSendCompleted(
+ PVOID pContext,
+ NTSTATUS status,
+ ULONG lInfo
+ );
+
+NTSTATUS
+UdpSendResponse(
+ IN ULONG lNameSize,
+ IN tNAMEHDR UNALIGNED *pNameHdrIn,
+ IN tNAMEADDR *pNameAddr,
+ IN PTDI_ADDRESS_IP pDestIpAddress,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN ULONG Rcode,
+ IN enum eNSTYPE NsType,
+ IN CTELockHandle OldIrq
+ );
+
+NTSTATUS
+UdpSendDatagram(
+ IN tDGRAM_SEND_TRACKING *pDgramTracker,
+ IN ULONG IpAddress,
+ IN PFILE_OBJECT TransportFileObject,
+ IN PVOID pCompletionRoutine,
+ IN PVOID CompletionContext,
+ IN USHORT Port,
+ IN ULONG Service
+ );
+
+PVOID
+CreatePdu(
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN ULONG IpAddress,
+ IN USHORT NameType,
+ IN enum eNSTYPE eNsType,
+ OUT PVOID *pHdrs,
+ OUT PULONG pLength,
+ IN tDGRAM_SEND_TRACKING *pTracker
+ );
+
+NTSTATUS
+TcpSessionStart(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN ULONG IpAddress,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pCompletionRoutine,
+ IN ULONG Port
+ );
+
+NTSTATUS
+TcpSendSessionResponse(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG lStatusCode,
+ IN ULONG lSessionStatus
+ );
+
+NTSTATUS
+TcpSendSession(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN tLOWERCONNECTION *LowerConn,
+ IN PVOID pCompletionRoutine
+ );
+
+NTSTATUS
+SendTcpDisconnect(
+ IN tLOWERCONNECTION *pLowerConnId
+ );
+
+NTSTATUS
+TcpDisconnect(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PVOID Timeout,
+ IN ULONG Flags,
+ IN BOOLEAN Wait
+ );
+
+VOID
+FreeTrackerOnDisconnect(
+ IN tDGRAM_SEND_TRACKING *pTracker
+ );
+
+VOID
+QueryRespDone(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo);
+
+VOID
+DisconnectDone(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo);
+
+
+//---------------------------------------------------------------------
+//
+// FROM tdiout.c
+//
+NTSTATUS
+TdiSendDatagram(
+ IN PTDI_REQUEST pRequestInfo,
+ IN PTDI_CONNECTION_INFORMATION pSendDgramInfo,
+ IN ULONG SendLength,
+ OUT PULONG pSentSize,
+ IN tBUFFER *pSendBuffer,
+ IN ULONG SendFlags
+ );
+PIRP
+NTAllocateNbtIrp(
+ IN PDEVICE_OBJECT DeviceObject
+ );
+NTSTATUS
+TdiConnect(
+ IN PTDI_REQUEST pRequestInfo,
+ IN ULONG lTimeout,
+ IN PTDI_CONNECTION_INFORMATION pSendInfo,
+ OUT PVOID pIrp
+ );
+NTSTATUS
+TdiSend(
+ IN PTDI_REQUEST pRequestInfo,
+ IN USHORT sFlags,
+ IN ULONG SendLength,
+ OUT PULONG pSentSize,
+ IN tBUFFER *pSendBuffer,
+ IN ULONG Flags
+ );
+
+NTSTATUS
+TdiDisconnect(
+ IN PTDI_REQUEST pRequestInfo,
+ IN PVOID lTimeout,
+ IN ULONG Flags,
+ IN PTDI_CONNECTION_INFORMATION pSendInfo,
+ IN PCTE_IRP pClientIrp,
+ IN BOOLEAN Wait
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM inbound.c
+//
+NTSTATUS
+QueryFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN USHORT OpCodeFlags,
+ IN BOOLEAN fBroadcast
+ );
+
+NTSTATUS
+RegResponseFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN USHORT OpCodeFlags
+ );
+
+NTSTATUS
+CheckRegistrationFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes
+ );
+
+NTSTATUS
+NameReleaseFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes
+ );
+
+NTSTATUS
+WackFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes
+ );
+
+VOID
+SetupRefreshTtl(
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN tNAMEADDR *pNameAddr,
+ IN LONG lNameSize
+ );
+
+BOOLEAN
+SrcIsNameServer(
+ IN ULONG SrcAddress,
+ IN USHORT SrcPort
+ );
+
+VOID
+SwitchToBackup(
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+BOOLEAN
+SrcIsUs(
+ IN ULONG SrcAddress
+ );
+
+NTSTATUS
+FindOnPendingList(
+ IN PUCHAR pName,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN BOOLEAN DontCheckTransactionId,
+ IN ULONG BytesToCompare,
+ OUT tNAMEADDR **ppNameAddr
+ );
+
+
+//---------------------------------------------------------------------
+//
+// FROM init.c
+//
+NTSTATUS
+InitNotOs(
+ void
+ ) ;
+
+NTSTATUS
+InitTimersNotOs(
+ void
+ );
+
+NTSTATUS
+StopInitTimers(
+ void
+ );
+
+VOID
+ReadParameters(
+ IN tNBTCONFIG *pConfig,
+ IN HANDLE ParmHandle
+ );
+
+VOID
+ReadParameters2(
+ IN tNBTCONFIG *pConfig,
+ IN HANDLE ParmHandle
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM parse.c
+//
+unsigned long
+LmGetIpAddr (
+ IN PUCHAR path,
+ IN PUCHAR target,
+ IN BOOLEAN recurse,
+ OUT BOOLEAN *bFindName
+ );
+
+VOID
+RemovePreloads (
+ );
+
+VOID
+RemoveName (
+ IN tNAMEADDR *pNameAddr
+ );
+
+LONG
+PrimeCache(
+ IN PUCHAR path,
+ IN PUCHAR ignored,
+ IN BOOLEAN recurse,
+ OUT BOOLEAN *ignored2
+ );
+
+NTSTATUS
+NtDnsNameResolve (
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID *pBuffer,
+ IN LONG Size,
+ IN PCTE_IRP pIrp
+ );
+
+NTSTATUS
+NtCheckForIPAddr (
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID *pBuffer,
+ IN LONG Size,
+ IN PCTE_IRP pIrp
+ );
+
+VOID
+StartIpAddrToSrvName(
+ IN NBT_WORK_ITEM_CONTEXT *Context,
+ IN ULONG *IpAddrsList,
+ IN BOOLEAN IpAddrResolved
+ );
+
+VOID
+StartConnWithBestAddr(
+ IN NBT_WORK_ITEM_CONTEXT *Context,
+ IN ULONG *IpAddrsList,
+ IN BOOLEAN IpAddrResolved
+ );
+
+NTSTATUS
+DoDnsResolve (
+ IN NBT_WORK_ITEM_CONTEXT *Context
+ );
+
+NTSTATUS
+DoCheckAddr (
+ IN NBT_WORK_ITEM_CONTEXT *Context
+ );
+
+NTSTATUS
+LmHostQueueRequest(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PVOID pClientContext,
+ IN PVOID ClientCompletion,
+ IN PVOID CallBackRoutine,
+ IN PVOID pDeviceContext,
+ IN CTELockHandle OldIrq
+ );
+
+tNAMEADDR *
+FindInDomainList (
+ IN PUCHAR pName,
+ IN PLIST_ENTRY pDomainHead
+ );
+
+VOID
+ScanLmHostFile (
+ IN PVOID Context
+ );
+
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+
+#endif // _NBTPROCS_H_
diff --git a/private/ntos/nbt/inc/ntprocs.h b/private/ntos/nbt/inc/ntprocs.h
new file mode 100644
index 000000000..8d5ef8bae
--- /dev/null
+++ b/private/ntos/nbt/inc/ntprocs.h
@@ -0,0 +1,845 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ NTProcs.c
+
+Abstract:
+
+
+ This file contains the function prototypes that are specific to the NT
+ portion of the NBT driver.
+
+Author:
+
+ Johnl 29-Mar-1993 Created
+
+Revision History:
+
+--*/
+
+//---------------------------------------------------------------------
+//
+// FROM DRIVER.C
+//
+NTSTATUS
+NbtDispatchCleanup(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP irp
+ );
+
+NTSTATUS
+NbtDispatchClose(
+ IN PDEVICE_OBJECT device,
+ IN PIRP irp
+ );
+
+NTSTATUS
+NbtDispatchCreate(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+NbtDispatchDevCtrl(
+ IN PDEVICE_OBJECT device,
+ IN PIRP irp
+ );
+
+NTSTATUS
+NbtDispatchInternalCtrl(
+ IN PDEVICE_OBJECT device,
+ IN PIRP irp
+ );
+
+PFILE_FULL_EA_INFORMATION
+FindInEA(
+ IN PFILE_FULL_EA_INFORMATION start,
+ IN PCHAR wanted
+ );
+
+
+USHORT
+GetDriverName(
+ IN PFILE_OBJECT pfileobj,
+ OUT PUNICODE_STRING name
+ );
+
+int
+shortreply(
+ IN PIRP pIrp,
+ IN int status,
+ IN int nbytes
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM NTISOL.C
+//
+NTSTATUS
+NTOpenControl(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTOpenAddr(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTOpenConnection(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+VOID
+NTSetFileObjectContexts(
+ IN PIRP pIrp,
+ IN PVOID FsContext,
+ IN PVOID FsContext2);
+
+VOID
+NTCompleteIOListen(
+ IN tCLIENTELE *pClientEle,
+ IN NTSTATUS Status);
+
+VOID
+NTIoComplete(
+ IN PIRP pIrp,
+ IN NTSTATUS Status,
+ IN ULONG SentLength);
+
+VOID
+NTCompleteRegistration(
+ IN tCLIENTELE *pClientEle,
+ IN NTSTATUS Status);
+
+NTSTATUS
+NTAssocAddress(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTCloseAddress(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+VOID
+NTClearFileObjectContext(
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+NTCloseConnection(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTSetSharedAccess(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp,
+ IN tADDRESSELE *pAddress);
+
+NTSTATUS
+NTCheckSharedAccess(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp,
+ IN tADDRESSELE *pAddress);
+
+NTSTATUS
+NTCleanUpAddress(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTCleanUpConnection(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+VOID
+DiscWaitCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+
+VOID
+NbtCancelListen(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP Irp
+ );
+
+VOID
+NTCancelRcvDgram(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+NTAccept(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTAssocAddress(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTDisAssociateAddress(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTConnect(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTDisconnect(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTListen(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+
+NTSTATUS
+NTQueryInformation(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTReceive(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTReceiveDatagram(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTSend(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTSendDatagram(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTSetEventHandler(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTSetInformation(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTCheckSetCancelRoutine(
+ IN PIRP pIrp,
+ IN PVOID CancelRoutine,
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+NTSTATUS
+NTSetCancelRoutine(
+ IN PIRP pIrp,
+ IN PVOID CancelRoutine,
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+VOID
+NTCancelSession(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+
+VOID
+DnsIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+
+VOID
+CheckAddrIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+
+VOID
+WaitForDnsIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+
+VOID
+NTSendSession(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN PVOID pCompletion);
+
+VOID
+NTSendDgramNoWindup(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN ULONG IpAddress,
+ IN PVOID pCompletion);
+
+NTSTATUS
+NTQueueToWorkerThread(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PVOID pClientContext,
+ IN PVOID ClientCompletion,
+ IN PVOID CallBackRoutine,
+ IN PVOID pDeviceContext
+ );
+
+VOID
+SecurityDelete(
+ IN PVOID pContext
+ );
+
+NTSTATUS
+DispatchIoctls(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp);
+
+NTSTATUS
+NTCancelCancelRoutine(
+ IN PIRP pIrp
+ );
+
+VOID
+NTClearContextCancel(
+ IN NBT_WORK_ITEM_CONTEXT *pContext
+ );
+
+VOID
+FindNameCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM NTUTIL.C
+//
+
+NTSTATUS
+NbtCreateDeviceObject(
+ PDRIVER_OBJECT DriverObject,
+ tNBTCONFIG *pConfig,
+ PUNICODE_STRING pBindName,
+ PUNICODE_STRING pExportName,
+ tADDRARRAY *pAddrs,
+ PUNICODE_STRING RegistryPath,
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ BOOLEAN fReuse,
+#endif
+ tDEVICECONTEXT **ppDeviceContext
+ );
+
+NTSTATUS
+NbtDestroyDeviceObject(
+ IN PVOID pBuffer
+ );
+
+NTSTATUS
+NbtProcessDhcpRequest(
+ tDEVICECONTEXT *pDeviceContext);
+
+NTSTATUS
+ConvertToUlong(
+ IN PUNICODE_STRING pucAddress,
+ OUT ULONG *pulValue);
+
+
+NTSTATUS
+NbtCreateAddressObjects(
+ IN ULONG IpAddress,
+ IN ULONG SubnetMask,
+ OUT tDEVICECONTEXT *pDeviceContext);
+
+VOID
+NbtGetMdl(
+ PMDL *ppMdl,
+ enum eBUFFER_TYPES eBuffType);
+
+NTSTATUS
+NbtInitMdlQ(
+ PSINGLE_LIST_ENTRY pListHead,
+ enum eBUFFER_TYPES eBuffType);
+
+NTSTATUS
+NTZwCloseFile(
+ IN HANDLE Handle
+ );
+
+
+NTSTATUS
+NTReReadRegistry(
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+NTSTATUS
+NbtInitIrpQ(
+ PLIST_ENTRY pListHead,
+ int iNumBuffers);
+
+NTSTATUS
+NbtLogEvent(
+ IN ULONG EventCode,
+ IN NTSTATUS Status
+ );
+
+NTSTATUS
+SaveClientSecurity(
+ IN tDGRAM_SEND_TRACKING *pTracker
+ );
+
+VOID
+NtDeleteClientSecurity(
+ IN tDGRAM_SEND_TRACKING *pTracker
+ );
+
+VOID
+LogLockOperation(
+ char operation,
+ PKSPIN_LOCK PSpinLock,
+ KIRQL OldIrql,
+ KIRQL NewIrql,
+ char *File,
+ int Line
+ );
+StrmpInitializeLockLog(
+ VOID
+ );
+VOID
+PadEntry(
+ char *EntryPtr
+ );
+
+NTSTATUS
+CloseAddressesWithTransport(
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+PVOID
+CTEAllocMemDebug(
+ IN ULONG Size,
+ IN PVOID pBuffer,
+ IN UCHAR *File,
+ IN ULONG Line
+ );
+
+VOID
+AcquireSpinLockDebug(
+ IN PKSPIN_LOCK pSpinLock,
+ IN PKIRQL pOldIrq,
+ IN UCHAR LockNumber
+ );
+VOID
+FreeSpinLockDebug(
+ IN PKSPIN_LOCK pSpinLock,
+ IN KIRQL OldIrq,
+ IN UCHAR LockNumber
+ );
+
+VOID
+AcquireSpinLockAtDpcDebug(
+ IN PKSPIN_LOCK pSpinLock,
+ IN UCHAR LockNumber
+ );
+
+VOID
+FreeSpinLockAtDpcDebug(
+ IN PKSPIN_LOCK pSpinLock,
+ IN UCHAR LockNumber
+ );
+
+VOID
+GetDgramMdl(
+ OUT PMDL *ppMdl);
+
+
+//---------------------------------------------------------------------
+//
+// FROM REGISTRY.C
+//
+NTSTATUS
+NbtReadRegistry(
+ IN PUNICODE_STRING RegistryPath,
+ IN PDRIVER_OBJECT DriverObject,
+ OUT tNBTCONFIG *pConfig,
+ OUT tDEVICES **ppBindDevices,
+ OUT tDEVICES **ppExportDevices,
+ OUT tADDRARRAY **ppAddrArray
+ );
+
+NTSTATUS
+ReadNameServerAddresses (
+ IN HANDLE NbtConfigHandle,
+ IN tDEVICES *BindDevices,
+ IN ULONG NumberDevices,
+ OUT tADDRARRAY **ppAddrArray
+ );
+
+NTSTATUS
+GetIPFromRegistry(
+ IN PUNICODE_STRING pucRegistryPath,
+ IN PUNICODE_STRING pucBindDevice,
+ OUT PULONG pulIpAddress,
+ OUT PULONG pulBroadcastAddress,
+ IN BOOL fWantDhcpAddresses
+ );
+
+NTSTATUS
+ReadElement(
+ IN HANDLE HandleToKey,
+ IN PWSTR pwsValueName,
+ OUT PUNICODE_STRING pucString
+ );
+
+NTSTATUS
+NTReadIniString (
+ IN HANDLE ParametersHandle,
+ IN PWSTR Key,
+ OUT PUCHAR *ppString
+ );
+
+ULONG
+NbtReadSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG DefaultValue,
+ IN ULONG MinimumValue
+ );
+
+NTSTATUS
+NTGetLmHostPath(
+ OUT PUCHAR *ppPath
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM tdihndlr.c
+//
+NTSTATUS
+Normal(
+ IN PVOID ReceiveEventContext,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID UNALIGNED pTsdu,
+ OUT PVOID *ppIrp
+ );
+NTSTATUS
+FillIrp(
+ IN PVOID ReceiveEventContext,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID UNALIGNED pTsdu,
+ OUT PVOID *ppIrp
+ );
+NTSTATUS
+IndicateBuffer(
+ IN PVOID ReceiveEventContext,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID UNALIGNED pTsdu,
+ OUT PVOID *ppIrp
+ );
+NTSTATUS
+PartialRcv(
+ IN PVOID ReceiveEventContext,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID UNALIGNED pTsdu,
+ OUT PVOID *ppIrp
+ );
+NTSTATUS
+TdiReceiveHandler (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID UNALIGNED Tsdu,
+ OUT PIRP *IoRequestPacket
+ );
+
+NTSTATUS
+PassRcvToTransport(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tCONNECTELE *pConnectEle,
+ IN PVOID pIoRequestPacket,
+ IN PULONG pRcvLength
+ );
+
+NTSTATUS
+CompletionRcv(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+NTSTATUS
+NtBuildIrpForReceive (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG Length,
+ OUT PVOID *ppIrp
+ );
+
+NTSTATUS
+SetEventHandler (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PFILE_OBJECT FileObject,
+ IN ULONG EventType,
+ IN PVOID EventHandler,
+ IN PVOID Context
+ );
+
+NTSTATUS
+SubmitTdiRequest (
+ IN PFILE_OBJECT FileObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+TdiConnectHandler (
+ IN PVOID pConnectEventContext,
+ IN int RemoteAddressLength,
+ IN PVOID pRemoteAddress,
+ IN int UserDataLength,
+ IN PVOID UNALIGNED pUserData,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ OUT CONNECTION_CONTEXT *pConnectionContext,
+ OUT PIRP *ppAcceptIrp
+ );
+
+NTSTATUS
+TdiDisconnectHandler (
+ PVOID EventContext,
+ PVOID ConnectionContext,
+ ULONG DisconnectDataLength,
+ PVOID UNALIGNED DisconnectData,
+ ULONG DisconnectInformationLength,
+ PVOID DisconnectInformation,
+ ULONG DisconnectIndicators
+ );
+NTSTATUS
+TdiRcvDatagramHandler(
+ IN PVOID pDgramEventContext,
+ IN int SourceAddressLength,
+ IN PVOID pSourceAddress,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN ULONG ReceiveDatagramFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *pBytesTaken,
+ IN PVOID UNALIGNED pTsdu,
+ OUT PIRP *pIoRequestPacket
+ );
+NTSTATUS
+TdiRcvNameSrvHandler(
+ IN PVOID pDgramEventContext,
+ IN int SourceAddressLength,
+ IN PVOID pSourceAddress,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN ULONG ReceiveDatagramFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *pBytesTaken,
+ IN PVOID UNALIGNED pTsdu,
+ OUT PIRP *pIoRequestPacket
+ );
+NTSTATUS
+TdiErrorHandler (
+ IN PVOID Context,
+ IN NTSTATUS Status
+ );
+
+NTSTATUS
+CompletionRcvDgram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+NTSTATUS
+NTProcessAcceptIrp(
+ IN PIRP pIrp,
+ OUT tCONNECTELE **ppConnEle
+ );
+
+NTSTATUS
+AllocateMdl (
+ IN tCONNECTELE *pConnEle
+ );
+
+VOID
+MakePartialMdl (
+ IN tCONNECTELE *pConnEle,
+ IN PIRP pIrp,
+ IN ULONG ToCopy
+ );
+
+NTSTATUS
+OutOfRsrcKill(
+ OUT tLOWERCONNECTION *pLowerConn);
+
+VOID
+CopyToStartofIndicate (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG DataTaken
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM tdicnct.c
+//
+NTSTATUS
+CreateDeviceString(
+ IN PWSTR AppendingString,
+ IN OUT PUNICODE_STRING pucDevice
+ );
+
+
+//---------------------------------------------------------------------
+//
+// FROM winsif.c
+//
+NTSTATUS
+NTOpenWinsAddr(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+NTCloseWinsAddr(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp);
+
+NTSTATUS
+RcvIrpFromWins (
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PCTE_IRP pIrp
+ );
+
+NTSTATUS
+PassNamePduToWins (
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameSrv,
+ IN ULONG uNumBytes
+ );
+
+NTSTATUS
+WinsSendDatagram(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp,
+ IN BOOLEAN MustSend);
+
+NTSTATUS
+WinsRegisterName(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN tNAMEADDR *pNameAddr,
+ IN PUCHAR pScope,
+ IN enum eNSTYPE eNsType
+ );
+
+
+//---------------------------------------------------------------------
+//
+// FROM ntpnp.c
+//
+
+#ifdef _PNP_POWER
+
+VOID
+AddressArrival(IN PTA_ADDRESS Addr);
+
+VOID
+AddressDeletion(IN PTA_ADDRESS Addr);
+
+extern HANDLE AddressChangeHandle;
+
+NTSTATUS
+NbtCreateNetBTDeviceObject(
+ PDRIVER_OBJECT DriverObject,
+ tNBTCONFIG *pConfig,
+ PUNICODE_STRING RegistryPath
+ );
+
+tDEVICECONTEXT *
+NbtFindIPAddress(
+ ULONG IpAddr
+ );
+
+NTSTATUS
+NbtNtPNPInit(
+ VOID
+ );
+
+VOID
+NbtFailedNtPNPInit(
+ VOID
+ );
+
+NTSTATUS
+NbtAddressAdd(
+ ULONG IpAddr,
+ PUNICODE_STRING pucBindString,
+ PUNICODE_STRING pucExportString,
+ PULONG Inst
+ );
+
+NTSTATUS
+NbtAddNewInterface (
+ IN PIRP pIrp,
+ IN PVOID *pBuffer,
+ IN ULONG Size
+ );
+
+VOID
+NbtAddressDelete(
+ ULONG IpAddr
+ );
+
+tDEVICECONTEXT *
+NbtFindBindName(
+ PUNICODE_STRING pucBindName
+ );
+
+#ifdef WATCHBIND
+VOID
+BindHandler(IN PUNICODE_STRING DeviceName);
+
+VOID
+UnbindHandler(IN PUNICODE_STRING DeviceName);
+
+extern HANDLE BindingHandle;
+#endif // WATCHBIND
+
+#endif
diff --git a/private/ntos/nbt/inc/oscfgnbt.h b/private/ntos/nbt/inc/oscfgnbt.h
new file mode 100644
index 000000000..51c3f803b
--- /dev/null
+++ b/private/ntos/nbt/inc/oscfgnbt.h
@@ -0,0 +1,85 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1992 **/
+/********************************************************************/
+/* :ts=4 */
+
+#ifndef OSCFG_INCLUDED
+#define OSCFG_INCLUDED
+
+
+#define net_short(x) ((((x)&0xff) << 8) | (((x)&0xff00) >> 8))
+
+//#define net_long(x) (((net_short((x)&0xffff)) << 16) | net_short((((x)&0xffff0000L)>>16)))
+#define net_long(x) (((((ulong)(x))&0xffL)<<24) | \
+ ((((ulong)(x))&0xff00L)<<8) | \
+ ((((ulong)(x))&0xff0000L)>>8) | \
+ ((((ulong)(x))&0xff000000L)>>24))
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+
+#ifdef VXD
+/////////////////////////////////////////////////////////////////////////////
+//
+// VXD definitions
+//
+////////////////////////////////////////////////////////////////////////////
+
+#include <stddef.h>
+
+#ifndef CHICAGO
+
+#pragma code_seg("_LTEXT", "LCODE")
+#pragma data_seg("_LDATA", "LCODE")
+
+//* pragma bodies for bracketing of initialization code.
+
+#define BEGIN_INIT code_seg("_ITEXT", "ICODE")
+#define BEGIN_INIT_DATA data_seg("_IDATA", "ICODE")
+#define END_INIT code_seg()
+#define END_INIT_DATA data_seg()
+
+#else // CHICAGO
+
+#define INNOCUOUS_PRAGMA warning(4:4206) // Source File is empty
+
+#define BEGIN_INIT INNOCUOUS_PRAGMA
+#define BEGIN_INIT_DATA INNOCUOUS_PRAGMA
+#define END_INIT INNOCUOUS_PRAGMA
+#define END_INIT_DATA INNOCUOUS_PRAGMA
+
+#endif // CHICAGO
+
+#else // VXD
+#ifdef NT
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// NT definitions
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include <ntos.h>
+#include <zwapi.h>
+
+#define BEGIN_INIT
+#define END_INIT
+
+#else // NT
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Definitions for additional environments go here
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#error Environment specific definitions missing
+
+#endif // NT
+
+#endif // VXD
+
+
+#endif // OSCFG_INCLUDED
diff --git a/private/ntos/nbt/inc/timer.h b/private/ntos/nbt/inc/timer.h
new file mode 100644
index 000000000..63c7e886f
--- /dev/null
+++ b/private/ntos/nbt/inc/timer.h
@@ -0,0 +1,89 @@
+//
+//
+// timer.h
+//
+// This file contains the typedefinitions for the timer code
+
+
+#ifndef __TIMERNBT_H
+#define __TIMERNBT_H
+
+// to convert a millisecond time to 100ns time
+//
+#define MILLISEC_TO_100NS 10000
+// the completion routine that the client must define
+typedef
+ VOID
+ (*COMPLETIONROUTINE)(
+ IN PVOID, // context
+ IN PVOID, // context2
+ IN PVOID); // timerqentry
+typedef
+ VOID
+ (*COMPLETIONCLIENT)(
+ IN PVOID,
+ IN NTSTATUS);
+
+// Timer Queue Entry - this entry looks after a timer event. It tracks who
+// should be called when the timeout occurs, the time in the future of the
+// timout, and a context value.
+typedef struct
+{
+ CTETimer VxdTimer ;
+ LIST_ENTRY Linkage;
+ PVOID Context;
+ PVOID Context2;
+ COMPLETIONROUTINE CompletionRoutine;
+ PVOID ClientContext;
+ COMPLETIONCLIENT ClientCompletion;
+ PVOID pCacheEntry; // entry in Remote or local cache
+ ULONG DeltaTime;
+ // this is set by the completionroutine to tell the timing system to
+ // restart the timer again, as opposed to disposing of the timer
+ USHORT Flags;
+ USHORT Retries; // number of times to restart the timer
+ UCHAR RefCount; // to tell if the timer is expiring or not
+
+}tTIMERQENTRY;
+
+// Flag bits for tTIMERQENTRY
+#define TIMER_RESTART 0x0001
+// to differentiate the broadcast timeouts from the timouts to the Name Service
+#define TIMER_MNODEBCAST 0x0002
+#define TIMER_DOING_EXPIRY 0x0004
+#define TIMER_NOT_STARTED 0x0008
+#define TIMER_RETIMED 0x0010 // timeout has changed, restart timer without any processing
+
+// The timer Q itself
+typedef struct
+{
+ DEFINE_LOCK_STRUCTURE( SpinLock )
+ LIST_ENTRY ActiveHead;
+ LIST_ENTRY FreeHead;
+
+} tTIMERQ;
+
+//
+// Function Prototype - this function is only called locally to this file
+//
+
+
+//
+// TimerExpiry routine - Called by kernel upon timer expiration. Note that
+// DeferredContext is the only argument used and must be named/used the
+// same between NT and WFW.
+//
+VOID
+TimerExpiry(
+#ifndef VXD
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArg1,
+ IN PVOID SystemArg2
+#else
+ IN CTEEvent * pCTEEvent,
+ IN PVOID DeferredContext
+#endif
+ ) ;
+
+#endif
diff --git a/private/ntos/nbt/inc/types.h b/private/ntos/nbt/inc/types.h
new file mode 100644
index 000000000..cf8b5e58b
--- /dev/null
+++ b/private/ntos/nbt/inc/types.h
@@ -0,0 +1,2449 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Types.h
+
+Abstract:
+
+
+ This file contains the typedefs and constants for Nbt.
+
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#ifndef _TYPES_H
+#define _TYPES_H
+
+#pragma warning( disable : 4103 )
+
+#include "nbtnt.h"
+#include "ctemacro.h"
+#include "debug.h"
+#include "timer.h"
+#include <nbtioctl.h>
+
+#ifndef VXD
+#include <netevent.h>
+#endif
+
+
+//----------------------------------------------------------------------------
+//
+// a flag to tell the transport to reindicate remaining data
+// currently not supported by the transport
+//
+#define TDI_RECEIVE_REINDICATE 0x00000200 // remaining TSDU should cause another indication to the client
+
+//
+// In debug builds, write flink and blink with invalid pointer values so that
+// if an entry is removed twice from a list, we bugcheck right there, instead
+// of being faced with a corrupted list some years later!
+//
+#if DBG
+#undef RemoveEntryList
+#define RemoveEntryList(Entry) {\
+ PLIST_ENTRY _EX_Blink;\
+ PLIST_ENTRY _EX_Flink;\
+ PLIST_ENTRY _EX_OrgEntry;\
+ _EX_OrgEntry = (Entry);\
+ _EX_Flink = (Entry)->Flink;\
+ _EX_Blink = (Entry)->Blink;\
+ _EX_Blink->Flink = _EX_Flink;\
+ _EX_Flink->Blink = _EX_Blink;\
+ _EX_OrgEntry->Flink = (LIST_ENTRY *)__LINE__;\
+ _EX_OrgEntry->Blink = (LIST_ENTRY *)__LINE__;\
+ }
+#endif
+
+//
+// Netbios name size restrictions
+//
+#define NETBIOS_NAME_SIZE 16
+#define MAX_DNS_NAME_LENGTH 256
+#define MAX_NBT_DGRAM_SIZE 512
+
+//
+// To distinguish NBNS server ipaddr from DNS server ipaddr in common routines
+//
+#define NBNS_MODE 1
+#define DNS_MODE 2
+
+// buffer size to start for registry reads
+#define REGISTRY_BUFF_SIZE 512
+//
+// this is the amount of memory that nbt will allocate max for datagram
+// sends, before it rejects datagram sends with insufficient resources, since
+// nbt buffers datagram sends to allow them to complete quickly to the
+// client. - 128k - it can be set via the registry using the Key
+// MaxDgramBuffering
+//
+#define DEFAULT_DGRAM_BUFFERING 0x20000
+
+//
+// the hash bucket structure - number of buckets - these should be set by
+// a value read from the registry (small/medium/large). If the registry
+// does not contain the values then these are used as defaults.
+//
+#define NUMBER_BUCKETS_LOCAL_HASH_TABLE 0x10
+#define NUMBER_BUCKETS_REMOTE_HASH_TABLE 0x10
+#define NUMBER_LOCAL_NAMES 10
+#define NUMBER_REMOTE_NAMES 10
+#define TIMER_Q_SIZE 20
+
+#define MEDIUM_NUMBER_BUCKETS_LOCAL_HASH_TABLE 0x80
+#define MEDIUM_NUMBER_BUCKETS_REMOTE_HASH_TABLE 0x80
+#define MEDIUM_NUMBER_LOCAL_NAMES 20
+#define MEDIUM_NUMBER_REMOTE_NAMES 100
+#define MEDIUM_TIMER_Q_SIZE 1000
+
+#define LARGE_NUMBER_BUCKETS_LOCAL_HASH_TABLE 255
+#define LARGE_NUMBER_BUCKETS_REMOTE_HASH_TABLE 255
+#define LARGE_NUMBER_LOCAL_NAMES 0xFFFF
+#define LARGE_NUMBER_REMOTE_NAMES 255
+#define LARGE_TIMER_Q_SIZE 0xFFFF
+
+//
+// max number of buffers of various types
+//
+#define NBT_INITIAL_NUM 2
+#define NBT_NUM_DGRAM_TRACKERS 0xFFFF
+#define NBT_NUM_INITIAL_CONNECTIONS 2
+#ifndef VXD
+#define NBT_NUM_IRPS 0xFFFF
+#define NBT_NUM_SESSION_MDLS 0xFFFF
+#define NBT_NUM_DGRAM_MDLS 0xFFFF
+#else
+#define NBT_NUM_SESSION_HDR 200
+#define NBT_NUM_SEND_CONTEXT 200
+#define NBT_NUM_RCV_CONTEXT 200
+#endif
+
+#define MEDIUM_NBT_NUM_DGRAM_TRACKERS 1000
+#define MEDIUM_NBT_NUM_INITIAL_CONNECTIONS 2
+#ifndef VXD
+#define MEDIUM_NBT_NUM_IRPS 1000
+#define MEDIUM_NBT_NUM_SESSION_MDLS 1000
+#define MEDIUM_NBT_NUM_DGRAM_MDLS 1000
+#else
+#define MEDIUM_NBT_NUM_SESSION_HDR 1000
+#define MEDIUM_NBT_NUM_SEND_CONTEXT 1000
+#define MEDIUM_NBT_NUM_RCV_CONTEXT 1000
+#endif
+
+#define LARGE_NBT_NUM_DGRAM_TRACKERS 0xFFFF
+#define LARGE_NBT_NUM_INITIAL_CONNECTIONS 5
+#ifndef VXD
+#define LARGE_NBT_NUM_IRPS 0xFFFF
+#define LARGE_NBT_NUM_SESSION_MDLS 0xFFFF
+#define LARGE_NBT_NUM_DGRAM_MDLS 0xFFFF
+#else
+#define LARGE_NBT_NUM_SESSION_HDR 0xFFFF
+#define LARGE_NBT_NUM_SEND_CONTEXT 0xFFFF
+#define LARGE_NBT_NUM_RCV_CONTEXT 0xFFFF
+#endif
+
+// ip loop back address - does not go out on wire
+//
+
+#define LOOP_BACK 0x7F000000 // in host order
+#define NET_MASK 0xC0 // used to get network number from ip address
+
+//
+// Nbt must indicate at least 128 bytes to its client, so it needs to be
+// able to buffer 128 bytes + the session header (4)
+//
+#define NBT_INDICATE_BUFFER_SIZE 132
+
+
+#define IS_NEG_RESPONSE(OpcodeFlags) (OpcodeFlags & FL_RCODE)
+#define IS_POS_RESPONSE(OpcodeFlags) (!(OpcodeFlags & FL_RCODE))
+
+//
+// where to locate or register a name - locally or on the network
+//
+enum eNbtLocation
+{
+ NBT_LOCAL,
+ NBT_REMOTE,
+ NBT_REMOTE_ALLOC_MEM
+};
+
+// these are bit mask values passed to freetracker in name.c to tell it what to do
+// to free a tracker
+//
+#define FREE_HDR 0x0001
+#define REMOVE_LIST 0x0002
+#define RELINK_TRACKER 0x0004
+
+//
+// List of Ip addresses for internet group names, terminated with an address
+// set to -1
+//
+typedef struct
+{
+ ULONG IpAddr[1];
+
+} tIPLIST;
+
+
+//
+// Hash Table basic structure
+//
+typedef struct
+{
+ LONG lNumBuckets;
+ DEFINE_LOCK_STRUCTURE( SpinLock )
+ enum eNbtLocation LocalRemote; // type of data stored inhash table
+ LIST_ENTRY Bucket[1]; // array uTableSize long of hash buckets
+
+} tHASHTABLE;
+
+//
+// the tNAMEADDR structure uses a bit mask to track which names are registered
+// on which adapters. To support up to 64 adapters on NT make this a ULONGLONG,
+// On the VXD the largest Long is 32 bits (they don't support _int64), so the
+// adapter limit is 32 for the VXD.
+//
+#ifndef VXD
+#define CTEULONGLONG ULONGLONG
+#else
+#define CTEULONGLONG ULONG
+#endif
+
+// the format of each element linked to the hash buckets
+//
+typedef struct _tNAMEADDR
+{
+ LIST_ENTRY Linkage; // used to link onto bucket chains
+
+ // for local names the scope is implied and is stored in the NbtGlobConfig
+ // structure, so the ptr to the scope block is used to point to the
+ // address element that corresponds to that name
+ union
+ {
+ struct _tNAMEADDR *pScope; // ptr to scope record in hash table
+ struct _Address *pAddressEle;// or ptr to address element
+ struct
+ {
+ USHORT MaxDomainAddrLength; // max # of ip addrs in Iplist for domain names from lmhosts
+ USHORT CurrentLength; // current # of above
+ };
+ };
+
+ // for group names, more than one IP address is stored, so the Ipaddress
+ // field becomes a ptr to another block that stores the IP addresses.
+ // In addition, the NameTypeState must be set to NAMETYPE_GROUP
+ union
+ {
+ ULONG IpAddress; // 4 byte IP address
+ tIPLIST *pIpList; // list of ip addresses for internet group names
+ };
+
+ PULONG pIpAddrsList; // list of ipaddrs (internet grp names,multihomed dns hosts etc.)
+
+ struct _TRACKER *pTracker; // contains tracker ptr during name resol. phase
+
+ // if the name is a scope name, it does not have timers started against
+ // it, so we can use the same memory to store the length of the scope name
+ union
+ {
+ tTIMERQENTRY *pTimer; // ptr to active timer entry
+ PVOID ScopeLength;
+ };
+ ULONG Ttl; // in milliseconds..ttl of name
+ ULONG RefCount; // if Greater than one, can't free memory
+
+ ULONG NameTypeState; // group or unique name + state
+
+ ULONG Verify; // for debug to tell remote from local names
+
+ CTEULONGLONG AdapterMask; // bit mask of adapters name registered on (MH)
+ CTEULONGLONG RefreshMask; // bit mask of adapters name refreshed
+
+ USHORT TimeOutCount; // Count to know when entry has timed out
+ BOOLEAN fProxyReq; //indicates whether the name was
+ //inserted as a result of hearing
+ //a name query or registration on the
+ //net
+#ifdef PROXY_NODE
+ BOOLEAN fPnode; //indicates whether the node type is
+ //a Pnode
+#endif
+
+ CHAR Name[NETBIOS_NAME_SIZE]; // 16 byte Net Bios name
+
+} tNAMEADDR;
+
+//
+// these values can be checked with a bit check since they are mutually
+// exclusive bits... uses the first nibble of the field
+//
+#define NAMETYPE_QUICK 0x0001 // set if name is Quick Unique or Quick Group
+#define NAMETYPE_UNIQUE 0x0002
+#define NAMETYPE_GROUP 0x0004
+#define NAMETYPE_INET_GROUP 0x0008
+#define NAMETYPE_SCOPE 0x1000
+//
+// values for NameTypeState.. the state of the name occupies the second nibble
+// of the field
+//
+#define STATE_RESOLVED 0x0010 // name query completed
+#define STATE_RELEASED 0x0020 // no longer active
+#define STATE_CONFLICT 0x0040 // proxy name addition to the name table
+#define STATE_RESOLVING 0x0080 // name is waiting for Query or Reg. to complete
+#define NAME_TYPE_MASK 0x000F
+#define NAME_STATE_MASK 0x00F0
+#define REFRESHED 0x0100 // set if the name refresh response was received
+#define TIMED_OUT 0x0200 // set if the timeout timer has happened once
+#define TIMED_OUT_DEREF 0x0400 // set if the hash timeout routine has derefed the name.
+#define PRELOADED 0x0800 // set if the entry is a preloaded entry - no timeout
+#define REFRESH_MASK 0x0F00
+
+#define LOCAL_NAME 0xDEAD0000
+#define REMOTE_NAME 0xFACF0000
+
+// the number of timeouts per refresh time. The timer expires 8 times and
+// refreshes every four (i.e. at twice the required refresh interval)
+#define REFRESH_DIVISOR 0x0008
+
+//
+// two flags used in the NbtTdiOpenAddress procedure to decide which
+// event handlers to setup
+//
+#define TCP_FLAG 0x00000001
+#define SESSION_FLAG 0x00000002
+
+//
+// these defines allow the code to run as either a Bnode or a Pnode
+// or a proxy
+//
+extern USHORT NodeType; // defined in Name.c
+#define BNODE 0x0001
+#define PNODE 0x0002
+#define MNODE 0x0004
+#define MSNODE 0x0008
+#define NODE_MASK 0x000F
+#define PROXY 0x0010
+#define DEFAULT_NODE_TYPE 0x1000
+
+//
+// NT wants Unicode, Vxd wants ANSI
+//
+#ifdef VXD
+ #define __ANSI_IF_VXD(str) str
+#else
+ #define __ANSI_IF_VXD(str) L##str
+#endif
+#define ANSI_IF_VXD( str ) __ANSI_IF_VXD( str )
+
+
+//
+// Wide String defintions of values to read from the registry
+//
+#define WS_NUM_BCASTS ANSI_IF_VXD("BcastNameQueryCount")
+#define WS_BCAST_TIMEOUT ANSI_IF_VXD("BcastQueryTimeout")
+#define WS_CACHE_TIMEOUT ANSI_IF_VXD("CacheTimeout")
+#define WS_NODE_TYPE ANSI_IF_VXD("NodeType")
+#define WS_NS_PORT_NUM ANSI_IF_VXD("NameServerPort")
+#define WS_DNS_PORT_NUM ANSI_IF_VXD("DnsServerPort")
+#define WS_NAMESRV_RETRIES ANSI_IF_VXD("NameSrvQueryCount")
+#define WS_NAMESRV_TIMEOUT ANSI_IF_VXD("NameSrvQueryTimeout")
+#define WS_NODE_SIZE ANSI_IF_VXD("Size/Small/Medium/Large")
+#define WS_KEEP_ALIVE ANSI_IF_VXD("SessionKeepAlive")
+#define WS_LMHOSTS_FILE ANSI_IF_VXD("LmHostFile")
+#define WS_ALLONES_BCAST ANSI_IF_VXD("BroadcastAddress")
+#define NBT_SCOPEID ANSI_IF_VXD("ScopeId")
+#define WS_RANDOM_ADAPTER ANSI_IF_VXD("RandomAdapter")
+#define WS_SINGLE_RESPONSE ANSI_IF_VXD("SingleResponse")
+#define WS_INITIAL_REFRESH ANSI_IF_VXD("InitialRefreshT.O.")
+#define WS_ENABLE_DNS ANSI_IF_VXD("EnableDns")
+#define WS_TRY_ALL_ADDRS ANSI_IF_VXD("TryAllIpAddrs")
+#define WS_ENABLE_LMHOSTS ANSI_IF_VXD("EnableLmhosts")
+#define WS_LMHOSTS_TIMEOUT ANSI_IF_VXD("LmhostsTimeout")
+#define WS_MAX_DGRAM_BUFFER ANSI_IF_VXD("MaxDgramBuffering")
+#define WS_ENABLE_PROXY_REG_CHECK ANSI_IF_VXD("EnableProxyRegCheck")
+#define WS_WINS_DOWN_TIMEOUT ANSI_IF_VXD("WinsDownTimeout")
+#define WS_MAX_CONNECTION_BACKLOG ANSI_IF_VXD("MaxConnBacklog")
+#define WS_CONNECTION_BACKLOG_INCREMENT ANSI_IF_VXD("BacklogIncrement")
+#define WS_REFRESH_OPCODE ANSI_IF_VXD("RefreshOpCode")
+
+#ifdef VXD
+#define VXD_NAMETABLE_SIZE_NAME ANSI_IF_VXD("NameTableSize")
+#define VXD_MIN_NAMETABLE_SIZE 1
+#define VXD_DEF_NAMETABLE_SIZE 17
+
+#define VXD_SESSIONTABLE_SIZE_NAME ANSI_IF_VXD("SessionTableSize")
+#define VXD_MIN_SESSIONTABLE_SIZE 1
+#define VXD_DEF_SESSIONTABLE_SIZE 255
+
+#define VXD_LANABASE_NAME ANSI_IF_VXD("LANABASE")
+#ifdef CHICAGO
+#define VXD_ANY_LANA 0xff
+#define VXD_DEF_LANABASE VXD_ANY_LANA
+#else
+#define VXD_DEF_LANABASE 0
+#endif
+
+#else
+
+#define WS_TRANSPORT_BIND_NAME ANSI_IF_VXD("TransportBindName")
+#endif
+
+#ifdef PROXY_NODE
+
+#define NODE_TYPE_MASK 0x60 //Mask for NodeType in NBFLAGS byte of
+ //Query response
+#define PNODE_VAL_IN_PKT 0x20 //A bit pattern of 01 in the NodeType fld
+ //of the Query response pkt indicates a
+ //P node
+#define WS_IS_IT_A_PROXY ANSI_IF_VXD("EnableProxy")
+
+#define IS_NOT_PROXY 0
+
+#endif
+#define NBT_PROXY_DBG(x) KdPrint(x)
+
+// Various Default values if the above values cannot be read from the
+// registry
+//
+#define DEFAULT_CACHE_TIMEOUT 360000 // 6 minutes in milliseconds
+#define MIN_CACHE_TIMEOUT 60000 // 1 minutes in milliseconds
+#define REMOTE_HASH_TIMEOUT 60000 // one minute timer
+//
+// timeouts - the defaults if the registry cannot be read.
+// (time is milliseconds)
+// The retry counts are the actual number of transmissions, not the number
+// of retries i.e. 3 means the first transmission and 2 retries. Except
+// for Bnode name registration where 3 registrations and 1 over write request
+// are sent.(effectively 4 are sent).
+//
+#define DEFAULT_NUMBER_RETRIES 3
+#define DEFAULT_RETRY_TIMEOUT 1500
+#define MIN_RETRY_TIMEOUT 100
+
+//#define MIN_RETRY_TIMEOUT 100
+
+// the broadcasts values below related to broadcast name service activity
+#define DEFAULT_NUMBER_BROADCASTS 3
+#define DEFAULT_BCAST_TIMEOUT 750
+#define MIN_BCAST_TIMEOUT 100
+
+#define DEFAULT_NODE_SIZE 1 // BNODE
+#define SMALL 1
+#define MEDIUM 2
+#define LARGE 3
+
+#define DEFAULT_KEEP_ALIVE 0xFFFFFFFF // disabled by default
+#define MIN_KEEP_ALIVE 60*1000 // 60 seconds in milliseconds
+//
+// The default is to use the subnet broadcast address for broadcasts rather
+// than use 0xffffffff(i.e. when BroadcastAddress is not defined in the
+// registery. If the registery variable BroadcastAddress is set to
+// something that cannot be read for some reason, then the broadcast address
+// gets set to this value.
+//
+#define DEFAULT_BCAST_ADDR 0xFFFFFFFF
+
+// a TTL value to use as a default (for refreshing names with WINS)
+//
+#define DEFAULT_TTL 5*60*1000
+
+//
+// Default TTL used for checking whether we need to switch back to the primary. currently 1 hour.
+//
+#define DEFAULT_SWITCH_TTL 1*60*60*1000 // millisecs.
+
+//
+// we refresh every 16 minutes / 8 - so no more than once every two
+// minutes until we reach WINS and get a new value
+//
+#define NBT_INITIAL_REFRESH_TTL 16*60*1000 // milliseconds
+#define MAX_REFRESH_CHECK_INTERVAL 600000 // 10 minutes in msec
+
+// don't allow the refresh mechanism to run any faster than once per 5 minutes
+#define NBT_MINIMUM_TTL 5*60*1000 // Milliseconds
+#define NBT_MAXIMUM_TTL 0xFFFFFFFF // larges ULONG (approx 50 days)
+
+//
+// the Mininimum and default timeouts to stop talking to WINS in the event
+// that we fail to reach it once.(i.e. temporarily stop using it)
+//
+#define DEFAULT_WINS_DOWN_TIMEOUT 15000 // 15 seconds
+#define MIN_WINS_DOWN_TIMEOUT 1000 // 1 second
+
+//
+// Default max connections that can be in backlog
+//
+#define DEFAULT_CONN_BACKLOG 1000
+#define MIN_CONN_BACKLOG 2
+#define MAX_CONNECTION_BACKLOG 40000 // we allow only upto 40000 outstanding connections (~4MB)
+
+//
+// Default max lower connection increment
+//
+#define DEFAULT_CONN_BACKLOG_INCREMENT 3
+#define MIN_CONN_BACKLOG_INCREMENT 3
+#define MAX_CONNECTION_BACKLOG_INCREMENT 20 // we allow only upto 20 new ones at a time
+
+// the minimum time to wait for a session setup pdu to complete - used to
+// start a timer in name.c
+#define NBT_SESSION_RETRY_TIMEOUT 10000 // 10 sec in milliseconds
+//
+// the number of times to attempt a session setup if the return code is
+// Called Name Present but insufficient resources (0x83) - or if the
+// destination does not have the name at all - in this case the session
+// is just setup one more time, not 3 more times
+//
+#define NBT_SESSION_SETUP_COUNT 3
+//
+// the following two lines allow proxy code to be compiled OUT if PROXY is not
+// defined
+//
+#define IF_PROXY(Node) if ((Node) & PROXY)
+#define END_PROXY
+
+#define IF_DEF_PROXY \
+#ifdef PROXY_NODE
+#define END_DEF_PROXY \
+#endif
+
+// Status code specific to NBT that is used in the RcvHndlrNotOs to indicate
+// that not enough data has been received, and more must be obtained.
+//
+#define STATUS_NEED_MORE_DATA 0xC0000999L
+
+#ifndef VXD
+
+//
+// Logging definitions
+//
+
+#define LOGSIZE 10000
+#define LOGWIDTH 32
+
+typedef char STRM_RESOURCE_LOG[LOGSIZE+1][LOGWIDTH];
+
+typedef struct {
+ STRM_RESOURCE_LOG Log;
+ CHAR Unused[3*LOGWIDTH]; // for overruns
+ int Index;
+} STRM_PROCESSOR_LOG, *PSTRM_PROCESSOR_LOG;
+
+/*
+ * Definitions for the error logging facility
+ */
+
+/*
+ * Maximum amount of data (binary dump data plus insertion strings) that
+ * can be added to an error log entry.
+ */
+#define MAX_ERROR_LOG_DATA_SIZE \
+ ( (ERROR_LOG_MAXIMUM_SIZE - sizeof(IO_ERROR_LOG_PACKET) + 4) & 0xFFFFFFFC )
+
+
+//
+// these are the names that NBT binds to, in TCP when it is opening address
+// objects or creating connections.
+//
+#define NBT_TCP_BIND_NAME L"\\Device\\Streams\\"
+#define NBT_MAINNAME_SERVICE L"NameServer"
+#define NBT_BACKUP_SERVER L"NameServerBackup"
+#define NBT_BIND L"Bind"
+#define NBT_EXPORT L"Export"
+#define NBT_PARAMETERS L"\\Parameters"
+#endif
+
+#define NBT_ADDRESS_TYPE 01
+#define NBT_CONNECTION_TYPE 02
+#define NBT_CONTROL_TYPE 03
+#define NBT_WINS_TYPE 04
+
+
+//
+// Maximum ip addresses that can be in an internet group - used as a sanity
+// check to prevent allocating hugh amounts of memory
+//
+#define NBT_MAX_INTERNET_GROUP_ADDRS 1000
+
+// define buffer types so we will know when we have allocated the maximum
+// allowed number of buffers - this enum serves as an array index into the
+// config data
+//
+enum eBUFFER_TYPES
+{
+ eNBT_DGRAM_TRACKER,
+ eNBT_TIMER_ENTRY,
+#ifndef VXD
+ eNBT_FREE_IRPS,
+ eNBT_FREE_SESSION_MDLS,
+ eNBT_DGRAM_MDLS,
+#else
+ eNBT_SESSION_HDR,
+ eNBT_SEND_CONTEXT,
+ eNBT_RCV_CONTEXT,
+#endif
+ eNBT_NUMBER_BUFFER_TYPES // this type must be last on the list
+};
+
+//
+// enumerate the types of name service broadcasts... either name registration
+// or name query
+//
+enum eNSTYPE
+{
+ eNAME_QUERY,
+ eDNS_NAME_QUERY,
+ eDIRECT_DNS_NAME_QUERY,
+ eNAME_QUERY_RESPONSE,
+ eNAME_REGISTRATION,
+ eNAME_REGISTRATION_OVERWRITE,
+ eNAME_REGISTRATION_RESPONSE,
+ eNAME_RELEASE,
+ eNAME_REFRESH
+};
+
+
+#define DIRECT_DNS_NAME_QUERY_BASE 0x8000
+
+//
+// Defines for the Verify elements of the handles passed to clients so that
+// we can determine if we recieved the correct handle back from the client
+// i.e. the Verify element must equal the correct define given here
+//
+#define NBT_VERIFY_ADDRESS 0x12345678
+#define NBT_VERIFY_LOWERCONN 0x11223344
+#define NBT_VERIFY_CONNECTION 0x87654321
+#define NBT_VERIFY_CONNECTION_DOWN 0x87654320
+#define NBT_VERIFY_CLIENT 0x18273645
+#define NBT_VERIFY_CLIENT_DOWN 0x18273640
+#define NBT_VERIFY_DEVCONTEXT 0x54637281
+#define NBT_VERIFY_CONTROL 0x56789123
+#define NBT_VERIFY_TRACKER 0x10231966
+#define NBT_VERIFY_BLOCKING_NCB 0x08121994
+//
+// Session Header types from the RFC's
+//
+#define NBT_SESSION_MESSAGE 0x00
+#define NBT_SESSION_REQUEST 0x81
+#define NBT_POSITIVE_SESSION_RESPONSE 0x82
+#define NBT_NEGATIVE_SESSION_RESPONSE 0x83
+#define NBT_RETARGET_SESSION_RESPONSE 0x84
+#define NBT_SESSION_KEEP_ALIVE 0x85
+#define NBT_SESSION_FLAGS 0x00 // flag byte of Session hdr = 0 always
+#define SESSION_NOT_LISTENING_ON_CALLED_NAME 0x80
+#define SESSION_NOT_LISTENING_FOR_CALLING_NAME 0x81
+#define SESSION_CALLED_NAME_NOT_PRESENT 0x82
+#define SESSION_CALLED_NAME_PRESENT_NO_RESRC 0x83
+#define SESSION_UNSPECIFIED_ERROR 0x8F
+
+//
+// Address Info structure used to return buffer in TDI_QUERY_ADDRESS_INFO
+//
+#include <packon.h>
+typedef struct
+{
+ ULONG ActivityCount;
+ TA_NETBIOS_ADDRESS NetbiosAddress;
+
+} tADDRESS_INFO;
+#include <packoff.h>
+//
+// Name Registration error codes per the RFC
+//
+#define REGISTRATION_NO_ERROR 0x0
+#define REGISTRATION_FORMAT_ERR 0x1
+#define REGISTRATION_SERVER_ERR 0x2
+#define REGISTRATION_UNSUPP_ERR 0x4
+#define REGISTRATION_REFUSED_ERR 0x5
+#define REGISTRATION_ACTIVE_ERR 0x6
+#define REGISTRATION_CONFLICT_ERR 0x7
+
+#define NBT_NAMESERVER_UDP_PORT 137 // port used by the Name Server
+#define NBT_DNSSERVER_UDP_PORT 53 // port used by the DNS server
+#define NBT_NAMESERVICE_UDP_PORT 137
+#define NBT_DATAGRAM_UDP_PORT 138
+#define NBT_SESSION_TCP_PORT 139
+#define IP_ANY_ADDRESS 0 // means broadcast IP address to IP
+#define WINS_SIGNATURE 0xFF // put into QdCount to tell signal name reg from this node
+//
+// whether an address is unique or a group address... these agree with the
+// values in TDI.H for TDI_ADDRESS_NETBIOS_TYPE_UNIQUE etc.. but are easier to
+// type!
+//
+enum eNbtAddrType
+{
+ NBT_UNIQUE,
+ NBT_GROUP,
+ NBT_QUICK_UNIQUE, // these two imply that the name is registered on the
+ NBT_QUICK_GROUP // net when it is claimed
+};
+
+//
+// this type defines the session hdr used to put session information
+// into each client pdu sent
+//
+#include <packon.h>
+typedef union
+{
+ union
+ {
+ struct
+ {
+ UCHAR Type;
+ UCHAR Flags;
+ USHORT Length;
+ };
+ ULONG UlongLength;
+ };
+ PSINGLE_LIST_ENTRY Next;
+} tSESSIONHDR;
+
+// Session response PDU
+typedef struct
+{
+ UCHAR Type;
+ UCHAR Flags;
+ USHORT Length;
+ UCHAR ErrorCode;
+
+} tSESSIONERROR;
+
+// Session Retarget response PDU
+typedef struct
+{
+ UCHAR Type;
+ UCHAR Flags;
+ USHORT Length;
+ ULONG IpAddress;
+ USHORT Port;
+
+} tSESSIONRETARGET;
+
+// the structure for the netbios name itself, which includes a length
+// byte at the start of it
+typedef struct
+{
+ UCHAR NameLength;
+ CHAR NetBiosName[1];
+
+} tNETBIOS_NAME;
+
+// session request packet...this is the first part of it. It still needs the
+// calling netbios name to be appended on the end, but we can't do that
+// until we know how long the Called Name is.
+typedef struct
+{
+ tSESSIONHDR Hdr;
+ tNETBIOS_NAME CalledName;
+
+} tSESSIONREQ;
+
+// the type definition to queue empty session header buffers in a LIST
+typedef union
+{
+ tSESSIONHDR Hdr;
+ LIST_ENTRY Linkage;
+} tSESSIONFREE;
+
+// this type definition describes the NetBios Datagram header format on the
+// wire
+typedef union
+{
+ struct
+ {
+ UCHAR MsgType;
+ UCHAR Flags;
+ USHORT DgramId;
+ ULONG SrcIpAddr;
+ USHORT SrcPort;
+ USHORT DgramLength;
+ USHORT PckOffset;
+ tNETBIOS_NAME SrcName;
+ };
+ LIST_ENTRY Linkage;
+
+} tDGRAMHDR;
+
+typedef struct
+{
+ UCHAR MsgType;
+ UCHAR Flags;
+ USHORT DgramId;
+ ULONG SrcIpAddr;
+ USHORT SrcPort;
+ UCHAR ErrorCode;
+
+} tDGRAMERROR;
+
+// define the header size since just taking the sizeof(tDGRAMHDR) will be 1 byte
+// too large and if for any reason this data structure changes later, things
+// fail to work for unknown reasons.... This size includes the Hdr + the
+// two half ascii src and dest names + the length byte in each name + the
+// It does
+// not include the scope. That must be added separately(times 2).
+#define DGRAM_HDR_SIZE 80
+#define MAX_SCOPE_LENGTH 255
+#define MAX_LABEL_LENGTH 63
+
+// Name Service header
+typedef struct
+{
+ USHORT TransactId;
+ USHORT OpCodeFlags;
+ UCHAR Zero1;
+ UCHAR QdCount;
+ UCHAR Zero2;
+ UCHAR AnCount;
+ UCHAR Zero3;
+ UCHAR NsCount;
+ UCHAR Zero4;
+ UCHAR ArCount;
+ tNETBIOS_NAME NameRR;
+
+} tNAMEHDR;
+
+//
+// the offset from the end of the question name to the field
+// in a name registration pdu ( includes 1 for the length byte of the name
+// since ConvertToAscii does not count that value
+//
+#define QUERY_NBFLAGS_OFFSET 10
+#define NBFLAGS_OFFSET 16
+#define IPADDRESS_OFFSET 18
+#define PTR_OFFSET 4 // offset to PTR in Name registration pdu
+#define NO_PTR_OFFSET 10 // offset to NbFlags after name
+#define PTR_SIGNATURE 0xC0 // ptrs to names in pdus start with C
+
+// the structure of a DNS label is the count of the number of bytes followed
+// by the label itself. Each part of a dot delimited name is a label.
+// Fred.ms.com is 3 labels.- Actually 4 labels where the last one is zero
+// length - hence all names end in a NULL
+typedef struct
+{
+ UCHAR uSizeLabel; // top two bits are set to 1 when next 14 bits point to actual label in msg.
+ CHAR pLabel[1]; // variable length of label -> 63 bytes
+
+} tDNS_LABEL;
+// top two bits set to signify a ptr to a name follows in the next 14 bits
+#define PTR_TO_NAME 0xC0
+
+// question section for the resource record modifiers
+typedef struct
+{
+ ULONG QuestionTypeClass;
+} tQUESTIONMODS;
+
+#define QUEST_NBINTERNET 0x00200001 // combined type/class
+#define QUEST_DNSINTERNET 0x00010001 // combined type/class for dns query
+#define QUEST_NETBIOS 0x0020 // General name service Resource Record
+#define QUEST_STATUS 0x0021 // Node Status resource Record
+#define QUEST_CLASS 0x0001 // internet class
+
+// Resource Record format - in the Name service packets
+// General format RrType = 0x20
+typedef struct
+{
+ tQUESTIONMODS Question;
+ tDNS_LABEL RrName;
+ ULONG RrTypeClass;
+ ULONG Ttl;
+ USHORT Length;
+ USHORT Flags;
+ ULONG IpAddress;
+
+} tGENERALRR;
+// Resource Record format - in the Name service packets
+// General format RrType = 0x20
+typedef struct
+{
+ ULONG RrTypeClass;
+ ULONG Ttl;
+ USHORT Length;
+ USHORT Flags;
+ ULONG IpAddress;
+
+} tQUERYRESP;
+
+// same as tQUERYRESP, except no Flags field
+// DNS servers return only 4 bytes of data (ipaddress): no flags.
+typedef struct
+{
+ USHORT RrType;
+ USHORT RrClass;
+ ULONG Ttl;
+ USHORT Length;
+ ULONG IpAddress;
+
+} tDNS_QUERYRESP;
+
+#define DNS_CNAME 5
+
+//
+// the format of the tail of the node status response message
+//
+typedef struct
+{
+ UCHAR Name[NETBIOS_NAME_SIZE];
+ UCHAR Flags;
+ UCHAR Resrved;
+
+} tNODENAME;
+
+typedef struct
+// the statistics portion of the node status message
+{
+ UCHAR UnitId[6];
+ UCHAR Jumpers;
+ UCHAR TestResult;
+ USHORT VersionNumber;
+ USHORT StatisticsPeriod;
+ USHORT NumberCrcs;
+ USHORT NumberAlignmentErrors;
+ USHORT NumberCollisions;
+ USHORT NumberSendAborts;
+ ULONG NumberSends;
+ ULONG NumberReceives;
+ USHORT NumberTransmits;
+ USHORT NumberNoResrcConditions;
+ USHORT NumberFreeCommandBlks;
+ USHORT TotalCommandBlocks;
+ USHORT MaxTotalCommandBlocks;
+ USHORT NumberPendingSessions;
+ USHORT MaxNumberPendingSessions;
+ USHORT MaxTotalSessionsPossible;
+ USHORT SessionDataPacketSize;
+
+} tSTATISTICS;
+
+typedef struct
+{
+ ULONG RrTypeClass;
+ ULONG Ttl;
+ USHORT Length;
+ UCHAR NumNames;
+ tNODENAME NodeName[1]; // there are NumNames of these
+
+} tNODESTATUS;
+
+typedef struct
+{
+ USHORT NbFlags;
+ ULONG IpAddr;
+
+} tADDSTRUCT;
+
+// Flags Definitions
+#define FL_GROUP 0x8000
+#define FL_BNODE 0x0000 // note that this has no bits set!!
+#define FL_PNODE 0x2000
+#define FL_MNODE 0x4000
+
+//Redirect type Address record - RrType = 0x01
+typedef struct
+{
+ USHORT RrType;
+ USHORT RrClass;
+ ULONG Ttl;
+ USHORT DataLength;
+ ULONG IpAddress;
+
+} tIPADDRRR;
+
+//Redirect type - Name Server Resource Record RrType = 0x02
+typedef struct
+{
+ USHORT RrType;
+ USHORT RrClass;
+ ULONG Ttl;
+ USHORT DataLength;
+ CHAR Name[1]; // name starts here for N bytes - till null
+
+} tREDIRECTRR;
+
+//Null type- WACK- RrType = 0x000A
+typedef struct
+{
+ USHORT RrType;
+ USHORT RrClass;
+ ULONG Zeroes;
+ USHORT Null;
+
+} tWACKRR;
+
+// definitions of the bits in the OpCode portion of the OpCodeFlag word
+// These definitions work on a 16 bit word rather than the 5 bit opcode and 7
+// bit flag
+#define NM_FLAGS_MASK 0x0078
+#define OP_RESPONSE 0x0080
+#define OP_QUERY 0x0000
+#define OP_REGISTRATION 0x0028
+#define OP_REGISTER_MULTI 0x0078 // new multihomed registration(Byte) op code
+#define OP_RELEASE 0x0030
+#define OP_WACK 0x0038
+#define OP_REFRESH 0x0040
+#define OP_REFRESH_UB 0x0048 // UB uses 9 instead of 8 (Ref. RFC 1002)
+#define REFRESH_OPCODE 0x8
+#define UB_REFRESH_OPCODE 0x9
+#define FL_RCODE 0x0F00
+#define FL_NAME_ACTIVE 0x0600 // WINS is reporting another name active
+#define FL_NAME_CONFLICT 0x0700 // another node is reporting name active
+#define FL_AUTHORITY 0x0004
+#define FL_TRUNCFLAG 0x0002
+#define FL_RECURDESIRE 0x0001
+#define FL_RECURAVAIL 0x8000
+#define FL_BROADCAST 0x1000
+#define FL_BROADCAST_BYTE 0x10
+// used to determine if the source is a Bnode for Datagram distribution
+#define SOURCE_NODE_MASK 0xFC
+
+// defines for the node status message
+#define GROUP_STATUS 0x80
+#define UNIQUE_STATUS 0x00
+#define NODE_NAME_PERM 0x02
+#define NODE_NAME_ACTIVE 0x04
+#define NODE_NAME_CONFLICT 0x08
+#define NODE_NAME_RELEASED 0x10
+#define STATUS_BNODE 0x00
+#define STATUS_PNODE 0x20
+#define STATUS_MNODE 0x40
+
+
+// Resource record defines - rrtype and rr class
+#define RR_NETBIOS 0x0020
+#define RR_INTERNET 0x0001
+
+// Name Query Response Codes
+#define QUERY_NOERROR 00
+#define FORMAT_ERROR 01
+#define SERVER_FAILURE 02
+#define NAME_ERROR 03
+#define UNSUPP_REQ 04
+#define REFUSED_ERROR 05
+#define ACTIVE_ERROR 06 // name is already active on another node
+#define CONFLICT_ERROR 07 // unique name is owned by more than one node
+
+
+//
+// Minimum Pdu lengths that will be accepted from the wire
+//
+#define NBT_MINIMUM_QUERY 50
+#define NBT_MINIMUM_WACK 58
+#define NBT_MINIMUM_REGRESPONSE 62
+#define NBT_MINIMUM_QUERYRESPONSE 56
+#define NBT_MINIMUM_REGREQUEST 68
+#define NBT_MINIMUM_NAME_QUERY_RESPONSE 56
+#define DNS_MINIMUM_QUERYRESPONSE 34
+
+typedef struct
+{
+ tDGRAMHDR DgramHdr;
+ CHAR SrcName[NETBIOS_NAME_SIZE];
+ CHAR DestName[NETBIOS_NAME_SIZE];
+
+} tDGRAM_NORMAL;
+
+typedef struct
+{
+ tDGRAMHDR DgramHdr;
+ UCHAR ErrorCode;
+
+} tDGRAM_ERROR;
+
+typedef struct
+{
+ tDGRAMHDR DgramHdr;
+ CHAR DestName[NETBIOS_NAME_SIZE];
+
+} tDGRAM_QUERY;
+
+#include <packoff.h>
+
+
+// the buffer type passed to the TDI routines so that the datagram or session
+// header can be included too.
+typedef struct
+{
+ ULONG HdrLength;
+ PVOID pDgramHdr;
+ ULONG Length;
+ PVOID pBuffer;
+
+} tBUFFER;
+
+//
+// This typedef is used by DgramHandlrNotOs to keep track of which client
+// is receiving a datagram and which client's need to also get the
+// datagram
+typedef struct
+{
+ struct _Address *pAddress;
+ ULONG ReceiveDatagramFlags;
+ PVOID pRemoteAddress;
+ ULONG RemoteAddressLength;
+ struct _Client *pClientEle;
+ BOOLEAN fUsingClientBuffer;
+ BOOLEAN fProxy; //used by PROXY code for getting the
+ //entire datagram. See
+ //CompletionRcvDgram in tdihndlrs.c
+
+} tCLIENTLIST;
+
+
+// Active Datagram Send List - a set of linked blocks that represent transactions
+// passed to the Transport TDI for execution... these blocks could be waiting
+// for name resolution or for the send to complete
+
+typedef struct _TRACKER
+{
+ // The type of address dictates the course of action, e.g., TDI_ADDRESS_NETBIOS_EX
+ // address avoids NETBIOS name registration. This encodes the desired address type
+ // associated with the connection or specified for the connection.
+
+ ULONG AddressType;
+
+ union {
+ // This datastructure tracks datagram sends.
+ struct
+ {
+ LIST_ENTRY Linkage;
+ LIST_ENTRY TrackerList;
+ ULONG Verify;
+ PCTE_IRP pClientIrp; // client's IRP
+ union
+ {
+ struct _Client *pClientEle; // client element block
+ struct _Connect *pConnEle; // connection element block
+ tNAMEADDR *p1CNameAddr; // DomainNames 1C pNameAddr - used sending datagrams
+ };
+
+ tBUFFER SendBuffer; // send buffer and header to send
+
+ PTDI_CONNECTION_INFORMATION pSendInfo;
+ struct _DeviceContext *pDeviceContext;
+ union
+ {
+ ULONG UNALIGNED *pHdrIpAddress; // address of ip address in pDgramHdr
+ tTIMERQENTRY *pTimer;
+ PVOID pNodeStatus; // node status response buffer
+ };
+
+ union
+ {
+ ULONG RefCount;
+ USHORT IpListIndex; // index into IpList for Group sends
+ USHORT SavedListIndex; //last index sent when timer was started
+ ULONG DestPort; // used by ReTarget to specify the dest port
+ };
+
+ union
+ {
+ PCHAR pDestName; // ptr to destination ASCII name
+ tNAMEADDR *pNameAddr; // ptr to name addres rec in hash tbl
+ };
+
+ #ifdef VXD
+ PUCHAR pchDomainName;
+ #endif
+ union
+ {
+ PVOID pTimeout; // used for the TCP connect timeout -from union below
+ ULONG NodeStatusLen;// pNodeStatus buffer length
+
+ // used for name queries and registrations to check if response has
+ // same transactionid
+ USHORT TransactionId;
+ ULONG RCount; // refcount used for datagram dist.
+ };
+
+ union
+ {
+ ULONG AllocatedLength; // used in Sending Dgrams to count mem allocated
+ ULONG RefConn; // used for NbtConnect
+ ULONG SrcIpAddress;// used for node status
+ };
+
+ //
+ // when two name queries go to the same name, this is the
+ // completion routine to call for this tracker queued to the first
+ // tracker.
+ //
+ COMPLETIONCLIENT CompletionRoutine;
+ USHORT Flags;
+ //#if DBG
+ LIST_ENTRY DebugLinkage; // to keep track of used trackers
+ //#endif
+
+ };
+ // this next version of the structure is used to track Session Sends as
+ // opposed to Datagram sends
+ struct
+ {
+ LIST_ENTRY Linkage;
+ LIST_ENTRY TrackerList;
+ ULONG Verify;
+ PCTE_IRP pClientIrp;
+ struct _Connect *pConnEle; // connection element block
+
+ tBUFFER SendBuffer; // send buffer and header to send
+
+ PTDI_CONNECTION_INFORMATION pSendInfo;
+ struct _DeviceContext *pDeviceContext;
+ tTIMERQENTRY *pTimer; // timer q entry
+
+ ULONG RefCount;
+
+ union
+ {
+ PCHAR pDestName; // ptr to destination ASCII name
+ tNAMEADDR *pNameAddr; // ptr to name addres rec in hash tbl
+ };
+
+ PVOID pTimeout; // used for the TCP connect timeout
+
+ ULONG RefConn;
+ //
+ // when two name queries go to the same name, this is the
+ // completion routine to call for this tracker queued to the first
+ // tracker.
+ //
+ COMPLETIONCLIENT CompletionRoutine;
+ USHORT Flags;
+
+ }Connect;
+ };
+
+ ULONG NumAddrs;
+ PULONG IpList;
+} tDGRAM_SEND_TRACKING;
+
+// this is the type of the procedure to call in the session receive handler
+// as data arrives - a different procedure per state
+typedef
+ NTSTATUS
+ (*tCURRENTSTATEPROC)(
+ PVOID ReceiveEventContext,
+ struct _LowerConnection *pLowerConn,
+ USHORT RcvFlags,
+ ULONG BytesIndicated,
+ ULONG BytesAvailable,
+ PULONG pBytesTaken,
+ PVOID UNALIGNED pTsdu,
+ PVOID *ppIrp);
+#ifdef VXD
+#define SetStateProc( pLower, StateProc )
+#else
+#define SetStateProc( pLower, StateProc ) ((pLower)->CurrentStateProc = (StateProc))
+#endif
+
+// this structure is necessary so that the NBT_WORK_ITEM_CONTEXT will have
+// the same structure in the vxd and NT cases.
+//
+typedef struct
+{
+ LIST_ENTRY List;
+} VXD_WORK_ITEM;
+
+//
+// Work Item structure for work items put on the Kernel Excutive worker threads
+//
+typedef struct
+{
+#ifndef VXD
+ WORK_QUEUE_ITEM Item; // Used by OS to queue these requests
+#else
+ VXD_WORK_ITEM Item;
+#endif
+ tDGRAM_SEND_TRACKING *pTracker;
+ PVOID pClientContext;
+ PVOID ClientCompletion;
+ BOOLEAN TimedOut;
+
+} NBT_WORK_ITEM_CONTEXT;
+
+
+#ifdef VXD
+
+typedef void (*DCCallback)( PVOID pContext ) ;
+
+typedef struct
+{
+ NBT_WORK_ITEM_CONTEXT dc_WIC ; // Must be first item in structure
+ CTEEvent dc_event ;
+ DCCallback dc_Callback ;
+ struct _DeviceContext *pDeviceContext;
+ LIST_ENTRY Linkage;
+} DELAYED_CALL_CONTEXT, *PDELAYED_CALL_CONTEXT ;
+
+typedef struct
+{
+ LIST_ENTRY Linkage;
+ ULONG Verify;
+ NCB *pNCB;
+ CTEBlockStruc *pWaitNCBBlock;
+ BOOL fNCBCompleted;
+ BOOL fBlocked;
+} BLOCKING_NCB_CONTEXT, *PBLOCKING_NCB_CONTEXT;
+
+#endif
+
+
+// A Listen is attached to a client element attached address element when a
+// client does a listen
+typedef VOID (*tRequestComplete)
+ (PVOID,
+ TDI_STATUS,
+ PVOID);
+
+typedef struct
+{
+ LIST_ENTRY Linkage;
+ PCTE_IRP pIrp; // IRP ptr for NT only (may not be true)
+ tRequestComplete CompletionRoutine;
+ PVOID pConnectEle; // the connection that the Listen is active on
+ PVOID Context;
+ ULONG Flags;
+ TDI_CONNECTION_INFORMATION *pConnInfo; // from a Listen
+ TDI_CONNECTION_INFORMATION *pReturnConnInfo; // from a Listen
+
+} tLISTENREQUESTS;
+
+typedef struct
+{
+ LIST_ENTRY Linkage;
+ PCTE_IRP pIrp; // IRP ptr for NT only (may not be true)
+ PVOID pRcvBuffer;
+ ULONG RcvLength;
+ PTDI_CONNECTION_INFORMATION ReceiveInfo;
+ PTDI_CONNECTION_INFORMATION ReturnedInfo;
+
+} tRCVELE;
+
+//
+// Values for the Flags element above
+#define NBT_BROADCAST 0x0001
+#define NBT_NAME_SERVER 0x0002
+#define NBT_NAME_SERVER_BACKUP 0x0004
+#define NBT_DNS_SERVER 0x0080
+#define NBT_DNS_SERVER_BACKUP 0x0100
+#define NBT_NAME_SERVICE 0x0010 // two flags used by Tdiout to send dgrams
+#define NBT_DATAGRAM_SERVICE 0x0020
+#define TRACKER_CANCELLED 0x0040
+#define WINS_NEG_RESPONSE 0x0200
+#define REMOTE_ADAPTER_STAT_FLAG 0x1000
+#define SESSION_SETUP_FLAG 0x2000
+#define DGRAM_SEND_FLAG 0x4000
+#define FIND_NAME_FLAG 0x8000
+
+
+//
+// this flag indicates that a datagram send is still outstanding in the
+// transport - it is set in the tracker flags field.
+//
+#define SEND_PENDING 0x0080
+
+
+// Completion routine definition for calls to the Udp... routines. This routine
+// type is called by the tdiout.c completion routine (the Irp completion routine),
+// so this is essentially the Nbt completion routine of the Irp.
+typedef
+ VOID
+ (*NBT_COMPLETION)(
+ IN PVOID, // context
+ IN NTSTATUS, // status
+ IN ULONG); // extra info
+
+
+// Define datagram types
+#define DIRECT_UNIQUE 0x10
+#define DIRECT_GROUP 0x11
+#define BROADCAST_DGRAM 0x12
+#define ERROR_DGRAM 0x13
+#define QUERY_REQUEST 0x14
+#define POS_QUERY_RESPONSE 0x15
+#define NEG_QUERY_RESPONSE 0x16
+
+// define datagra flags byte values
+#define FIRST_DGRAM 0x02
+#define MORE_DGRAMS 0x01
+
+// the possible states of the lower connection to the transport
+enum eSTATE
+{
+ NBT_IDLE, // not Transport connection
+ NBT_ASSOCIATED, // associated with an address element
+ NBT_RECONNECTING, // waiting for the Worker thread to run NbtConnect again
+ NBT_CONNECTING, // establishing Transport connection
+ NBT_SESSION_INBOUND, // waiting for a session request after tcp connection setup inbound
+ NBT_SESSION_WAITACCEPT, // waiting for accept after a listen has been satisfied
+ NBT_SESSION_OUTBOUND, // waiting for a session response after tcp connection setup
+ NBT_SESSION_UP, // got positive response
+ NBT_DISCONNECTING, // sent a disconnect down to Tcp, but it hasn't completed yet
+ NBT_DISCONNECTED // a session has been disconnected but not closed with TCP yet
+};
+
+//
+// The default disconnect timeout used in several places in name.c
+//
+#define DEFAULT_DISC_TIMEOUT 10 // seconds
+
+//
+// this is the value that the IpListIndex is set to when the last datagram
+// has been sent.
+//
+#define LAST_DGRAM_DISTRIBUTION 0xFFFD
+#define END_DGRAM_DISTRIBUTION 0xFFFE
+// max 500 millisec timeout for ARP on dgram send before netbt sends the next
+// datagram.
+#define DGRAM_SEND_TIMEOUT 500
+
+//
+// These are other states for connections that are not explicitly used by
+// NBT but are returned on the NbtQueryConnectionList call.
+//
+#define LISTENING 20;
+#define UNBOUND 21;
+
+// Lower Connection states that deal with receiving to the indicate buffer
+#define NORMAL 0
+#define INDICATE_BUFFER 1
+#define FILL_IRP 2
+#define PARTIAL_RCV 3
+
+// Spin Lock Numbers. Each structure is assigned a number so that locks are
+// always acquired in the same order. The CTESpinLock code checks the lock
+// number before setting the spin lock and asserts if it is higher than
+// the current one. This prevents deadlocks.
+#define JOINT_LOCK 0x0001
+#define ADDRESS_LOCK 0x0002
+#define DEVICE_LOCK 0x0004
+#define CONNECT_LOCK 0x0008
+#define CLIENT_LOCK 0x0010
+#define LOWERCON_LOCK 0x0020
+#define NBTCONFIG_LOCK 0x0040
+
+
+// these are two bits to indicated the state of a client element record
+//
+#define NBT_ACTIVE 1
+#define NBT_DOWN 0
+
+// this structure is used by the parse.c to hold on to an Irp from the
+// lmhsvc.dll that is used for checking IP addr reachability.
+//
+typedef struct
+{
+ PCTE_IRP QueryIrp; // irp passed down from lmhsvc.dll
+ LIST_ENTRY ToResolve; // linked list of names Q'd to resolve
+ PVOID Context; // currently resolving name context block
+ BOOLEAN ResolvingNow; // irp is in user mode doing a resolve
+} tCHECK_ADDR;
+
+// this structure is used by the parse.c to hold on to an Irp from the
+// lmhsvc.dll that is used for DNS name queries
+//
+typedef struct
+{
+ PCTE_IRP QueryIrp; // irp passed down from lmhsvc.dll
+ LIST_ENTRY ToResolve; // linked list of names Q'd to resolve
+ PVOID Context; // currently resolving name context block
+ BOOLEAN ResolvingNow; // irp is in user mode doing a resolve
+} tDNS_QUERIES;
+
+//
+// This structure is used to queue lmhost name query requests while one
+// request is pending with the file system, so that we do not use more than
+// one executive worker thread
+//
+typedef struct
+{
+ LIST_ENTRY ToResolve; // linked list of names Q'd to resolve
+ PVOID Context; // currently resolving name context block
+ BOOLEAN ResolvingNow; // irp is in user mode doing a resolve
+ tTIMERQENTRY *pTimer; // non null if the timer is running
+
+} tLMHOST_QUERIES;
+
+#define DEFAULT_LMHOST_TIMEOUT 6000 // 6-12 to wait for lmhost or DNS query
+#define MIN_LMHOST_TIMEOUT 1000 // 1 seconds min
+
+//
+// Lmhosts Domain Controller List - keeps a list of #DOM names that have
+// been retrieved from the LMhosts file
+//
+typedef struct
+{
+ LIST_ENTRY DomainList;
+
+} tDOMAIN_LIST;
+//
+// The pIpList of a domain name starts with 6 ulongs of space
+//
+#define INITIAL_DOM_SIZE sizeof(ULONG)*6
+
+#ifndef VXD
+//
+// This structure keeps track of the WINS recv Irp and any datagram
+// queued to go up to WINS (name service datagrams)
+//
+typedef struct
+{
+ PCTE_IRP RcvIrp; // irp passed down from WINS for Rcv
+ LIST_ENTRY RcvList; // linked list of Datagrams Q'd to rcv
+ LIST_ENTRY SendList; // Dgrams Q'd to be sent
+ ULONG RcvMemoryAllocated; // bytes buffered so far
+ ULONG RcvMemoryMax; // max # of bytes to buffer on Rcv
+ ULONG SendMemoryAllocated;// bytes for buffering dgram sends
+ ULONG SendMemoryMax; // max allowed for buffering dgram sends
+
+ struct _DeviceContext *pDeviceContext; // the devicecontext used by wins for sends
+
+} tWINS_INFO;
+
+//
+// Wins Rcv Buffer structure
+//
+typedef struct
+{
+ LIST_ENTRY Linkage;
+ ULONG DgramLength;
+ tREM_ADDRESS Address;
+
+} tWINSRCV_BUFFER;
+#endif
+// Connection Database...
+// this tracks the connection to the transport and the address of the
+// endpoint (Net Bios name) and a connection Context to return to the client
+// on each Event (i.e. Receive event or Disconnect Event ).
+typedef struct _Connect
+{
+ LIST_ENTRY Linkage; // ptrs to next in chain
+
+ ULONG Verify; //3 set to a known value to verify block
+ DEFINE_LOCK_STRUCTURE( SpinLock ) //4 to lock access on an MP machine
+ struct _LowerConnection *pLowerConnId; //5 connection ID to transport
+ struct _Client *pClientEle; //6 ptr to client record
+
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ struct _DeviceContext *pDeviceContext;
+#endif
+
+ LIST_ENTRY Active; //7-8 list of Active sends
+ LIST_ENTRY RcvHead; //9-10 List of Rcv Buffers
+
+ CONNECTION_CONTEXT ConnectContext;//11 ret to client on each event
+
+ UCHAR RemoteName[NETBIOS_NAME_SIZE] ; // 12
+#ifndef VXD
+ // keep an extra MDL per connection if needed to handle multichunk rcvs
+ PMDL pNewMdl; // 16
+
+ // this tracks how full the current Mdl is when we are in the FILLIRP
+ // state.
+ ULONG CurrentRcvLen; //17 #of bytes to recv for Irp
+ ULONG FreeBytesInMdl;//18 (upper word)
+#else
+ //
+ // Name of remote session endpoint
+ //
+ UCHAR RTO ; // NB Receive timeout (in 1/2 sec)
+ UCHAR STO ; // NB Send timeout
+ USHORT Flags ;
+#endif
+
+ ULONG TotalPcktLen; //18 length of session packet
+ ULONG BytesInXport; //19 number of bytes left in the transport
+ ULONG BytesRcvd; //20 number of bytes recvd so far
+ ULONG ReceiveIndicated; //20 count of number of rcv indicates not handled yet
+
+ union
+ {
+#ifndef VXD
+ // the next MDL in the chain to use as a basis for a partial MDL
+ PMDL pNextMdl; //21
+#endif
+ tDGRAM_SEND_TRACKING *pTracker; //21 used when session is setup to pt to tracker for name query
+ };
+
+ // the amount of the Mdl/NCB that has been filled
+ ULONG OffsetFromStart;// 22
+ PCTE_IRP pIrp; //23 IRP ptr for a send
+ PCTE_IRP pIrpClose; //24 IRP for an NtClose
+ // if a disconnect comes down when the connection is pending stash
+ // the disconnect irp here till the connect completes
+ PCTE_IRP pIrpDisc; //25
+
+ PCTE_IRP pIrpRcv; //26 IRP that client has passed down for a session Rcv
+
+ LONG RefCount; //27 number of active requests on the connection
+ enum eSTATE state; //28
+
+ // need to know if this is an originating connection when we cleanup so
+ // we know if a connection in the freelist should be deleted or not
+ BOOLEAN Orig; //29
+ UCHAR LockNumber; //29 spin lock number for this struct
+
+ // the session setup is tried this number of times in case the
+ // destination is in between listens, if the return code is
+ // NoListen, then retry session setup.
+ UCHAR SessionSetupCount; //29
+
+ // this tracks if the disconnect was an abort or a normal release
+ // it is passed to the client as a return status in NbtDisconnect if
+ // the client does a disconnect wait.
+ UCHAR DiscFlag; //29
+ BOOLEAN JunkMsgFlag;
+
+#ifdef RASAUTODIAL
+ // this field is TRUE if an automatic connection is in progress
+ // for this connection. we use this to prevent an infinite
+ // number of automatic connection attempts to the same address.
+ BOOLEAN fAutoConnecting;
+
+ // this field is TRUE if this connection has already been
+ // autoconnected.
+ BOOLEAN fAutoConnected;
+#endif
+
+ // The NetBt Connection logic manages a pool of lower connection blocks. These
+ // entries are replenished with every associate call made from the client.
+ // The entries are removed with a fresh invocation to NbtConnectCommon.
+ // Since it is conceivable that multiple invocations to NbtConnectCommon can be
+ // made this state needs to be recorded in the connect element.
+ BOOLEAN LowerConnBlockRemoved;
+
+ // The DNS status of the remote name is recorded in this field. It is set to
+ // FALSE on creation of a tCONNECTELE instance and changed to TRUE if the
+ // DNS resolution for the Remote Name fails. This is used to throttle back
+ // subsequent requests for the same DNS name.
+ BOOLEAN RemoteNameDoesNotExistInDNS;
+
+ // The type of address over which the connection was established. This
+ // field is used to store the type of address that was used to establish the
+ // connection. The valid address types are the TDI_ADDRESS_TYPE_* constants
+ // defined in tdi.h
+ ULONG AddressType;
+
+} tCONNECTELE;
+
+
+// a list of connections to the transport. For each connection opened
+// to the transport, the connection context is set to the address of this
+// block so that when info comes in on the conection, the pUpperConnection
+// ptr can be used to find the client connection
+typedef struct _LowerConnection
+{
+ LIST_ENTRY Linkage;
+ ULONG Verify;
+ DEFINE_LOCK_STRUCTURE( SpinLock )
+ struct _Connect *pUpperConnection; //4 ptr to upper conn. to client
+
+ // Contains Handle/Object of a TDI Connection for incoming connections
+#ifndef VXD
+ HANDLE FileHandle; // file handle for connection to transport
+#endif
+ CTE_ADDR_HANDLE pFileObject; // file object for the connection
+
+ // Address object handles - used for outgoing connections only since
+ // inbound connections are all bound to the same address object (port 139)
+ //
+ // The VXD uses only pAddrFileObject which contains the openned address
+ // handle (used for compatibility with existing code).
+ //
+#ifndef VXD
+ HANDLE AddrFileHandle; // file handle for the address
+#endif
+ CTE_ADDR_HANDLE pAddrFileObject; // file object for the address
+
+ // this is a ptr to the device context so we can put the connection
+ // back on its free list at the end of the session.
+ struct _DeviceContext *pDeviceContext;
+
+#ifndef VXD
+ // This mdl holds up to 128 bytes that are mandated by TDI as the
+ // minimum number of bytes for an indication
+ //
+ PMDL pIndicateMdl; //11
+
+ // these are for query provider statistics
+ ULONGLONG BytesRcvd; //12
+ ULONGLONG BytesSent; //14
+
+ // keep the initial value of the Client's MDL
+ // incase we receive a session PDU in several chunks, then we can set the
+ // MDL back to its original value when it has all been received
+ PMDL pMdl; //16
+
+ // the number of bytes in the indicate buffer
+ USHORT BytesInIndicate;
+#else
+ //
+ // The VXD only has to worry about getting enough data for the
+ // session header (as opposed to 128 bytes for the NT indication
+ // buffer).
+ tSESSIONHDR Hdr ;
+
+ // these are for query provider statistics
+ ULONG BytesRcvd;
+ ULONG BytesSent;
+
+ //
+ // When a lower connection goes into the partial receive state, it is
+ // put on the pClientEle->PartialRcvHead until an NCB is submitted to
+ // get that data
+ //
+ LIST_ENTRY PartialRcvList ;
+
+ //
+ // Number of bytes in Hdr
+ //
+ USHORT BytesInHdr ;
+#endif
+ // the receive state = Normal/UseIndic/FillIrp/PartialRcv
+ USHORT StateRcv; //17
+
+ ULONG SrcIpAddr; //18
+
+ enum eSTATE State; //19
+
+ LONG RefCount; //20 the number of active users of record
+
+ //
+ // Irp to complete after disconnect completes
+ //
+ PCTE_IRP pIrp; // 21
+
+#ifndef VXD
+ // in the receive handler this procedure variable is used to point to the
+ // procedure to call for the current state (Normal,FillIrp,IndicateBuff,RcvPartial)
+
+ tCURRENTSTATEPROC CurrentStateProc; //22
+
+ // this boolean tells if we are receiving into the indicate buffer right now
+ BOOLEAN bReceivingToIndicateBuffer; //23
+#endif
+
+ UCHAR LockNumber; // spin lock number for this struct
+
+ // set to TRUE if the connection originated on this side
+ BOOLEAN bOriginator;
+ // this flag is set true when executing the session Rcv Handler so we
+ // can detect this state and not free ConnEle or LowerConn memory.
+ BOOLEAN InRcvHandler;
+ //
+ // This is set when the IP address changes, and the connection is
+ // still open, so that when the connection is cleaned up it is
+ // closed rather than being put back on the free list
+ //
+ BOOLEAN DestroyConnection; //24
+
+ //
+ // Set when this connection is queued onto the OutOfRsrc list in NbtConfig to
+ // indicate to DeleteLowerConn not to try and remove this from any list.
+ //
+ BOOLEAN OutOfRsrcFlag;
+
+ //
+ // Was this allocated to tackle the TCP/IP SynAttack problem?
+ //
+ BOOLEAN SpecialAlloc;
+
+#ifdef VXD
+ BOOLEAN fOnPartialRcvList;
+#endif
+
+} tLOWERCONNECTION;
+
+
+// the Client list is just a list of linked blocks where the address of the
+// block is the HANDLE returned to the client - The client block is linked onto
+// the chain of clients that have opened the address.
+typedef struct _Client
+{
+ LIST_ENTRY Linkage; // double linked list to next client
+ ULONG Verify; // set to a known value to verify block
+ PCTE_IRP pIrp; // IRP ptr for NT only... during name registration
+ DEFINE_LOCK_STRUCTURE( SpinLock ) // spin lock synch. access to structure
+
+ struct _Address *pAddress; // ptr to address object that this client is Q'd on
+ LIST_ENTRY ConnectHead; // list of connections
+ LIST_ENTRY ConnectActive; // list of connections that are in use
+
+ LIST_ENTRY RcvDgramHead; // List of dgram buffers to recv into
+
+ LIST_ENTRY ListenHead; // List of Active Listens
+
+ LIST_ENTRY SndDgrams; // a doubly linked list of Dgrams to send
+
+#ifdef VXD
+ LIST_ENTRY RcvAnyHead ; // List of RCV_CONTEXT for NCB Receive any
+
+ BOOL fDeregistered; // TRUE if the name has been deleted and
+ // we are waiting for sessions to close
+#endif
+ PTDI_IND_CONNECT evConnect; // Client Event to call
+ PVOID ConEvContext; // EVENT Context to pass to client
+ PTDI_IND_RECEIVE evReceive;
+ PVOID RcvEvContext;
+ PTDI_IND_DISCONNECT evDisconnect;
+ PVOID DiscEvContext;
+ PTDI_IND_ERROR evError;
+ PVOID ErrorEvContext;
+ PTDI_IND_RECEIVE_DATAGRAM evRcvDgram;
+ PVOID RcvDgramEvContext;
+ PTDI_IND_RECEIVE_EXPEDITED evRcvExpedited;
+ PVOID RcvExpedEvContext;
+ PTDI_IND_SEND_POSSIBLE evSendPossible;
+ PVOID SendPossEvContext;
+
+ struct _DeviceContext *pDeviceContext; // the device context associated with this connection
+
+ LONG RefCount;
+ UCHAR LockNumber; // spin lock number for this struct
+ // if several clients register the same name at the same time this
+ // flag is set. It is reset in RegisterCompletion.
+ BOOLEAN WaitingForRegistration;
+
+ // The address type of the associated AddressEle structure. This is
+ // a stashed value of the original value stored in the address element.
+ ULONG AddressType;
+ UCHAR EndpointName[NETBIOS_NAME_SIZE];
+ BOOLEAN ExtendedAddress;
+} tCLIENTELE;
+
+// The Address List is a set of blocks that contain the netbios names active
+// on the node. Each time a connection request comes in or a datagram is
+// received, the destination name must be found in the address list.
+// There is one of these for each Netbios name in the system, although there
+// can be more than one client attached to each of these. In addition,
+// a client can open the same name for several different adapters. In this case
+// the nbt code first finds the ptr to this address element, and then it walks
+// the client list to find a client with a "deviceContext" (ip address) that
+// matches the adapter that the pdu came in on.
+typedef struct _Address
+{
+ LIST_ENTRY Linkage; // link to next item in list
+ ULONG Verify; // set to a known value to verify block
+ DEFINE_LOCK_STRUCTURE( SpinLock ) // to lock structure on MP machines
+
+ LIST_ENTRY ClientHead; // list of client records Q'd against address
+ tNAMEADDR *pNameAddr; // ptr to entry in hash table
+ LONG RefCount;
+ struct _DeviceContext *pDeviceContext; // the device context associated with this connection
+
+#ifndef VXD
+ SHARE_ACCESS ShareAccess; // Used for checking share access
+ PSECURITY_DESCRIPTOR SecurityDescriptor; // used to hold ACLs on the address
+
+#endif
+
+ USHORT NameType; // Group or Unique NAMETYPE_UNIQUE or group
+
+ UCHAR LockNumber; // spin lock number for this struct
+
+ // signals Dgram Rcv handler that more than one client exists - set
+ // when names are added in NbtOpenAddress
+ BOOLEAN MultiClients;
+
+ // The type of address specified in opening the connection object. The values
+ // are the same as the TDI_ADDRESS_TYPE_ constants. Currently the only valid
+ // values are TDI_ADDRESS_TYPE_NETBIOS and TDI_ADDRESS_TYPE_NETBIOS_EX.
+ ULONG AddressType;
+} tADDRESSELE;
+
+
+// this structure is used to store the addresses of the name servers
+// for each adapter - it is used in Registry.c and Driver.c
+//
+typedef struct
+{
+ ULONG NameServerAddress;
+ ULONG BackupServer;
+
+}tADDRARRAY;
+
+typedef struct
+{
+ UCHAR Address[6];
+
+}tMAC_ADDRESS;
+
+// this type is the device context which includes NBT specific data
+// that is initialized when "DriverEntry" is called.
+//
+
+//
+// The transport type is used to distinguish the additional transport types
+// that can be supported, NETBT framing without NETBIOS name resolution/registration
+// and NETBIOS over TCP. The transport type is stored as part of all the upper
+// level data structures. This enables us to reuse NETBT code and expose multiple
+// device objects at the top level. Currently these are not exposed. In preparation
+// for exporting multiple transport device objects the DeviceContext has been
+// reorganized.
+// The elements that would be common to all the device objects have been gathered
+// together in tCOMMONDEVICECONTEXT. This will include an enumerated type to
+// distinguish between the various device objects in the future. Currently there is only
+// one device context and the fields that belong to it are listed ...
+//
+// RegistrationHandle -- PNP power,
+// enumerated type distinguishing the types.
+//
+
+typedef struct _DeviceContext
+{
+#ifndef VXD
+ // the I/O system's device object
+ DEVICE_OBJECT DeviceObject;
+#endif // !VXD
+
+ // a linkage to store these in a linked list in the tNBTCONFIG structure
+ LIST_ENTRY Linkage;
+
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ // a linkage to store free, re-usable contexts in a linked list in the tNBTCONFIG structure
+ LIST_ENTRY FreeLinkage;
+#endif
+
+ // to lock access to this structure on an MP machine
+ DEFINE_LOCK_STRUCTURE( SpinLock )
+
+ // a value to verify that this is a device context record
+ ULONG Verify;
+
+ // ulong since we use interlocked ops to manipulate it.
+ ULONG IsDestroyed;
+
+#if DBG
+ BOOLEAN IsDynamic;
+#endif
+ // connections that the clients have created
+ LIST_ENTRY UpConnectionInUse;
+
+ // connections to the transport provider that are currently in use
+ LIST_ENTRY LowerConnection; // blocks in use
+
+ // these are connected to the transport but not currently connected to
+ // a client(upper) connection - ready to accept an incoming session
+ //
+ LIST_ENTRY LowerConnFreeHead; // list of unused connections down
+
+#ifdef VXD
+ //
+ // List of RCV_CONTEXT for NCB Receive any from any request (is here
+ // because any receive to anybody can satisfy this request)
+ //
+ LIST_ENTRY RcvAnyFromAnyHead ;
+
+ //
+ // When a lower connection goes into the partial receive state, it is
+ // put on this list until an NCB is submitted to get the data
+ //
+ LIST_ENTRY PartialRcvHead ;
+
+ //
+ // Dgram receives that specified a name number of 0xff (ANY_NAME)
+ //
+ LIST_ENTRY RcvDGAnyFromAnyHead ;
+
+ //
+ // all events that are scheduled for later on this device context
+ //
+ LIST_ENTRY DelayedEvents;
+
+ tCLIENTELE * * pNameTable ; // Name table for this adapter
+ tCONNECTELE * * pSessionTable ; // Session table
+ UCHAR iNcbNum ; // Next available NCB Num in table
+ UCHAR iLSNum ; // Next avaialabe LSN in table
+ UCHAR cMaxNames ; // Maximum adapter names (exc. Perm Name)
+ UCHAR cMaxSessions ; // Maximum sessions
+
+ UCHAR IPIndex ; // Index of IP address in IP driver
+ UCHAR iLana; // Lana index
+ BOOLEAN fDeviceUp; // to avoid ncb's coming when not ready
+ UCHAR Pad1[1] ;
+
+ HANDLE hBroadcastAddress ;// Handle openned with NbtOpenAddress on '*'
+#else
+ // name of the device to bind to - *TODO* remove from this struct.
+ UNICODE_STRING BindName;
+ // name exported by this device
+ UNICODE_STRING ExportName;
+#endif //!VXD
+
+ // addresses that need to be opened with the transport
+ ULONG IpAddress;
+ ULONG SubnetMask;
+ ULONG BroadcastAddress;
+ ULONG NetMask; // mask for the network number
+
+ //
+ // handles for open addresses to the transport provider
+ //
+ // The VXD uses only the p*FileObject fields which contain TDI Addresses
+ // or connection IDs
+ //
+#ifndef VXD
+ HANDLE hNameServer; // from ZwCreateFile
+ PDEVICE_OBJECT pNameServerDeviceObject; // from pObject->DeviceObject
+#endif //!VXD
+ CTE_ADDR_HANDLE pNameServerFileObject; // from ObReferenceObjectByHandle(hNameServer)
+
+#ifndef VXD
+ HANDLE hDgram;
+ PDEVICE_OBJECT pDgramDeviceObject;
+#endif //!VXD
+ CTE_ADDR_HANDLE pDgramFileObject;
+
+#ifndef VXD
+ HANDLE hSession;
+ PDEVICE_OBJECT pSessionDeviceObject;
+#endif //!VXD
+ CTE_ADDR_HANDLE pSessionFileObject;
+
+#ifndef VXD
+ // these are handles to the transport control object, so we can do things
+ // like query provider info... *TODO* this info may not need to be kept
+ // around... just set it up once and then drop it?
+ HANDLE hControl;
+ PDEVICE_OBJECT pControlDeviceObject;
+ PFILE_OBJECT pControlFileObject;
+
+#endif //!VXD
+
+ // the Ip Address of the Name Server
+ ULONG lNameServerAddress;
+ ULONG lBackupServer;
+
+#ifdef VXD
+ // the Ip Addresses of the DNS Servers
+ ULONG lDnsServerAddress;
+ ULONG lDnsBackupServer;
+#endif //VXD
+ // ptr to the permanent name client record in case we have to delete
+ // it later.
+ tCLIENTELE *pPermClient;
+
+ // this is a bit mask, a bit shifted to the bit location corresponding
+ // to this adapter number
+ CTEULONGLONG AdapterNumber; // bit mask for adapters 1->64 (1-32 for VXD)
+ tMAC_ADDRESS MacAddress;
+
+ UCHAR LockNumber; // spin lock number for this struct
+ BOOLEAN RefreshToBackup; // flag to say switch to backup nameserver
+ BOOLEAN PointToPoint; // set if the transport is RAS device
+ BOOLEAN WinsIsDown; // per Devcontext flag to tell us not to contact WINS for 15 sec.
+#ifdef _PNP_POWER
+ HANDLE RegistrationHandle; // Handle returned from TdiRegisterDeviceObject.
+#endif // _PNP_POWER
+ ULONG InstanceNumber;
+} tDEVICECONTEXT;
+
+
+#ifdef VXD
+
+typedef struct
+{
+ //
+ // Book keeping.
+ //
+ LIST_ENTRY Linkage;
+ tTIMERQENTRY *pTimer; // ptr to active timer entry
+ tDEVICECONTEXT *pDeviceContext;
+ //
+ // Domain name for next query.
+ //
+ PUCHAR pchDomainName;
+ //
+ // Flags to track progress.
+ //
+ USHORT Flags;
+ //
+ // Transaction ID used in name query.
+ //
+ USHORT TransactId;
+ //
+ // Client fields follow.
+ //
+ NCB *pNCB;
+ PUCHAR pzDnsName;
+ PULONG pIpAddress;
+
+} DNS_DIRECT_WORK_ITEM_CONTEXT, *PDNS_DIRECT_WORK_ITEM_CONTEXT;
+
+typedef struct
+{
+ tDEVICECONTEXT *pDeviceContext;
+ TDI_CONNECTION_INFORMATION
+ SendInfo;
+ TA_IP_ADDRESS NameServerAddress;
+ tBUFFER SendBuffer; // send buffer and header to send
+ tNAMEHDR NameHdr;
+} DNS_DIRECT_SEND_CONTEXT, *PDNS_DIRECT_SEND_CONTEXT;
+
+//
+// Flag bits useful for DNS direct name queries.
+//
+#define DNS_DIRECT_CANCELLED 0x0001 // request cancelled
+#define DNS_DIRECT_DNS_SERVER 0x0002 // going to main DNS
+#define DNS_DIRECT_DNS_BACKUP 0x0004 // going to main DNS
+#define DNS_DIRECT_TIMED_OUT 0x0008 // request timed out
+#define DNS_DIRECT_NAME_HAS_DOTS 0x0010 // name has dots in it, could be fully formed
+ // DNS specifier
+#define DNS_DIRECT_ANSWERED 0x0020 // This query has been answered
+#endif // VXD
+
+#ifndef VXD
+// configuration information is passed between the registry reading
+// code and the driver entry code in this data structure
+// see ntdef.h for this type....
+typedef struct
+{
+ // this has a pointer to the actual string buffer in it, so to work
+ // correctly this buffer pointer must be set to point to an actual
+ // buffer
+ UNICODE_STRING Names[NBT_MAXIMUM_BINDINGS];
+ PVOID RegistrySpace; // space to store the above strings
+ // allocated with ExAllocatePool
+
+}tDEVICES;
+#endif
+
+// this is the control object for all of NBT that tracks a variety
+// of counts etc. There is a ptr to this in the GlobConfig structure
+// below so that we can delete it later at clean up time
+typedef struct
+{
+ DEFINE_LOCK_STRUCTURE( SpinLock )
+ // a value to verify that this is a device context record
+ ULONG Verify;
+
+ // this is a LARGE structure of goodies that is returned to the client
+ // when they do a QueryInformation on TDI_PROVIDER_INFO
+ TDI_PROVIDER_INFO ProviderInfo;
+
+
+} tCONTROLOBJECT;
+
+// overall spin lock to coordinate access to timer entries and hash tables
+// at the same time. Always get the joint lock FIRST and then either the
+// hash or timer lock. Be sure not to get both hash and timer locks or
+// dead lock could result
+//
+typedef struct
+{
+ DEFINE_LOCK_STRUCTURE( SpinLock )
+ UCHAR LockNumber;
+
+ //
+ // In non-debug builds, the lock structure goes away altogther
+ //
+ #if defined(VXD) && !defined( DEBUG )
+ int iDummy ;
+ #endif
+
+}tJOINTLOCK;
+
+// Keep an Irp around for the out of resource case, so that we can still
+// disconnection a connection with the transport
+// Also, keep a KDPC handy so if we can use it in case lot of connections
+// are to be killed in succession
+//
+typedef struct
+{
+ PIRP pIrp;
+ LIST_ENTRY ConnectionHead;
+#ifndef VXD
+ PKDPC pDpc;
+#endif
+
+} tOUTOF_RSRC;
+
+#define MAXIMUM_PROCESSORS 32
+
+// this type holds NBT configuration information... is globally available
+// within NBT using NbtConfig.
+typedef struct
+{
+ DEFINE_LOCK_STRUCTURE( SpinLock )
+ int NumConnections; // number of connections set in registry
+ int NumAddresses; // number of addresses node supports set in reg.
+
+ // linked list of device contexts, one per network adapter (tDEVICECONTEXT)
+ LIST_ENTRY DeviceContexts;
+
+ // linked list of device contexts, one per network adapter (tDEVICECONTEXT)
+ LIST_ENTRY FreeDevCtx;
+
+ // counts to track how many buffer have been allocated so far
+ USHORT iCurrentNumBuff[eNBT_NUMBER_BUFFER_TYPES];
+ USHORT iMaxNumBuff[eNBT_NUMBER_BUFFER_TYPES];
+ USHORT iBufferSize[eNBT_NUMBER_BUFFER_TYPES];
+
+ USHORT Pad1 ; // eNBT_NUMBER_BUFFER_TYPES is odd
+
+ // buffers to track Dgram sends...
+ LIST_ENTRY DgramTrackerFreeQ;
+
+ // list of node status messages being sent
+ LIST_ENTRY NodeStatusHead;
+
+ // allocated addresses in a linked list
+ LIST_ENTRY AddressHead;
+
+ LIST_ENTRY PendingNameQueries;
+
+#ifdef VXD
+ LIST_ENTRY DNSDirectNameQueries;
+#endif // VXD
+
+#ifndef VXD
+ // a ptr to keep track of the memory allocated to the control object
+ tCONTROLOBJECT *pControlObj;
+
+ PDRIVER_OBJECT DriverObject;
+
+ // a list of Irps, since we need them at Dispatch level and can't create
+ // them at that level
+ LIST_ENTRY IrpFreeList;
+
+ // a list of MDLs for session sends to speed up sending session PDUs
+ SINGLE_LIST_ENTRY SessionMdlFreeSingleList;
+
+ // a list of MDLs for datagram sends to speed up sending
+ SINGLE_LIST_ENTRY DgramMdlFreeSingleList;
+
+ // a ptr to the registry Node for Netbt so we can read it later if
+ // DHCP requests come down.
+ UNICODE_STRING pRegistry;
+
+ // a ptr to the name of the transport (i.e. \Device\Streams\")
+ PWSTR pTcpBindName;
+#else
+ //
+ // Tracks all Send NCBs for the express purpose of checking if they have
+ // timed out yet.
+ //
+ LIST_ENTRY SendTimeoutHead ;
+
+ //
+ // Free buffer lists, correspond to eNBT_SESSION_HDR,
+ // eNBT_SEND_CONTEXT and eNBT_RCV_CONTEXT buffer types respectively.
+ //
+ LIST_ENTRY SessionBufferFreeList ;
+ LIST_ENTRY SendContextFreeList ; // TDI_SEND_CONTEXT (not SEND_CONTEXT!)
+ LIST_ENTRY RcvContextFreeList ;
+ //
+ // all events that are scheduled for later (that apply to all device contexts)
+ //
+ LIST_ENTRY DelayedEvents;
+ LIST_ENTRY BlockingNcbs;
+#endif //VXD
+
+ // hash table to keep track of local and remote names
+ tHASHTABLE *pLocalHashTbl;
+ tHASHTABLE *pRemoteHashTbl;
+
+#ifndef VXD
+ // This structure keeps an Irp ready to disconnect a connection in the
+ // event we run out of resources and cannot do anything else. It also allows
+ // connections to Q up for disconnection.
+ tOUTOF_RSRC OutOfRsrc;
+
+ // used to hold Address exclusively while registering - when mucking with
+ // ShareAccess and the security descriptors
+ //
+ ERESOURCE Resource;
+#endif
+
+ USHORT uNumDevices; // number of adapters counted in registry
+ USHORT uNumLocalNames; // size of remote hash table for Pnode
+ USHORT uNumRemoteNames; // size of remote hash table for Proxy
+ USHORT uNumBucketsRemote;
+ USHORT uNumBucketsLocal;
+ USHORT TimerQSize; // the number of timer Q blocks
+
+#ifdef _PNP_POWER
+ USHORT uDevicesStarted; // bindings/devices/local IP addresses in use
+ USHORT Pad2;
+#endif // _PNP_POWER
+
+ LONG uBcastTimeout; // timeout between Broadcasts
+ LONG uRetryTimeout; // timeout between retries
+
+ USHORT uNumRetries; // number of times to send a dgram - applies to Queries to NS as well as Dgrams
+ USHORT uNumBcasts; // number of times to bcast name queries
+
+ // the scope must begin with a length byte that gives the length of the next
+ // label, and it must end with a NULL indicating the zero length root
+ USHORT ScopeLength; // number of bytes in scope including the 0 on the end
+ USHORT SizeTransportAddress; // number of bytes in transport addr (sizeof TDI_ADDRESS_IP for IP)
+ PCHAR pScope; // scope if ScopeLength > 0
+
+ // a ptr to the netbios name record in the local hash table
+ tNAMEADDR *pBcastNetbiosName;
+
+ // the shortest Ttl of any name registered by this node and the name that
+ // has the shortest Ttl
+ ULONG MinimumTtl;
+ ULONG RefreshDivisor;
+ ULONG RemoteHashTimeout;
+ //
+ // This is amount of time to stop talking to WINS when we fail to contact
+ // it on a name registration. Nominally around 5 seconds - configurable.
+ //
+ ULONG WinsDownTimeout;
+
+ // timer entry for refreshing names with WINS
+ tTIMERQENTRY *pRefreshTimer;
+ tTIMERQENTRY *pSessionKeepAliveTimer;
+ tTIMERQENTRY *pRemoteHashTimer;
+
+ ULONG InitialRefreshTimeout; // to refresh names to WINS till we hear from WINS
+ ULONG KeepAliveTimeout; // keep alive timeout for sessions
+ ULONG RegistryBcastAddr;
+
+ // the number of connections to restore when the ip address becomes
+ // valid again.
+ //
+ USHORT DhcpNumConnections;
+ USHORT CurrentHashBucket;
+
+ USHORT PduNodeType; // node type that goes into NS pdus
+ USHORT TransactionId; // for name service request, to number them
+
+ USHORT NameServerPort; // UDP port to send queries/reg to (on the name server)
+#ifdef VXD
+ USHORT DnsServerPort; // UDP port to send DNS queries to (on the dns server)
+#endif
+ USHORT sTimeoutCount; // current time segment we are on for refresh
+
+ USHORT LastSwitchTimeoutCount; // Count to know when we last switched to primary
+
+ // this spin lock is used to coordinate access to the timer Q and the
+ // hash tables when either a timer is expiring or a name service PDU
+ // has come in from the wire. This lock must be acquired first, and
+ // then the timer Q lock.
+ tJOINTLOCK JointLock;
+ UCHAR LockNumber; // spin lock number for this struct
+ USHORT RemoteTimeoutCount; // how long to timeout remote hash entries
+
+ // if 1, then use -1 for bcast addr - if 0 use subnet broadcast address
+ BOOLEAN UseRegistryBcastAddr;
+
+ // the maximum amount of buffering that we will do for sent datagrams
+ // This is also used by Wins to determine inbound and outbound buffer
+ // limits.
+ ULONG MaxDgramBuffering;
+ // this is the time that a name query can spend queued waiting for the
+ // the worker thread to service it. - default is 30 seconds.
+ ULONG LmHostsTimeout;
+
+ PUCHAR pLmHosts;
+ ULONG PathLength; // the length of the directory portion of pLmHosts
+#ifdef VXD
+ PUCHAR pHosts; // path to the hosts file
+ PUCHAR pDomainName; // primary domain: used during DNS resolution
+ PUCHAR pDNSDomains; // "other domains"
+
+ // chicago needs this!
+ // to avoid having to read parms at CreateDevice time, we read some parms from
+ // registry at init time and store them here (ndis may not honour our request to
+ // read registry at arbitrary times e.g. dhcp renew occurs).
+ //
+ ULONG lRegistryNameServerAddress;
+ ULONG lRegistryBackupServer;
+
+ ULONG lRegistryDnsServerAddress;
+ ULONG lRegistryDnsBackupServer;
+
+ USHORT lRegistryMaxNames;
+ USHORT lRegistryMaxSessions;
+#endif
+
+ UCHAR AdapterCount;// number of network adapters.
+ BOOLEAN MultiHomed; // True if NBT is bound to more than one adapter
+ BOOLEAN SingleResponse; // if TRUE it means do NOT send all ip addresses on a name query request
+
+ // if TRUE randomly select an IP addr on name query response rather than
+ // return the address that the request came in on.
+ BOOLEAN SelectAdapter;
+
+ // This boolean tells Nbt to attempt name resolutions with DNS
+ BOOLEAN ResolveWithDns;
+ // Nbt tries all addresses of a multi-homed machine if this is TRUE (by default its TRUE).
+ BOOLEAN TryAllAddr;
+ // This boolean tells Nbt to attempt name resolutions with LMhosts
+ BOOLEAN EnableLmHosts;
+ // This allows a proxy to do name queries to WINS to check Bnode name
+ // registrations. By default this functionality is off since it could
+ // be a RAS client who has changed its IP address and the proxy will
+ // deny the new registration since it only does a query and not a
+ // registration/challenge.
+ //
+ BOOLEAN EnableProxyRegCheck;
+
+ // set to true when a name refresh is active so a second refresh timeout
+ // will not start another refresh over the first one
+ BOOLEAN DoingRefreshNow;
+ UCHAR CurrProc;
+ //
+ // allow the refresh op code to be registry configured since UB uses
+ // a different value than everyone else due to an ambiguity in the spec.
+ // - we use 0x40 and they use 0x48 (8, or 9 in the RFC)
+ //
+ USHORT OpRefresh;
+
+#if DBG && !defined(VXD)
+ // NBT's current lock level - an array entry for up to 32 processors
+ ULONG CurrentLockNumber[MAXIMUM_PROCESSORS];
+ DEFINE_LOCK_STRUCTURE(DbgSpinLock)
+#endif
+
+ ULONG InterfaceIndex;
+
+#if DBG
+ ULONG ActualNumSpecialLowerConn;
+#endif
+ ULONG NumQueuedForAlloc;
+ ULONG NumSpecialLowerConn;
+ ULONG MaxBackLog;
+ ULONG SpecialConnIncrement;
+
+} tNBTCONFIG;
+
+extern tNBTCONFIG *pNbtGlobConfig;
+extern tNBTCONFIG NbtConfig;
+extern tNAMESTATS_INFO NameStatsInfo;
+extern tCHECK_ADDR CheckAddr;
+extern tDNS_QUERIES DnsQueries; // defined in parse.c
+extern tDOMAIN_LIST DomainNames;
+#ifndef VXD
+extern tWINS_INFO *pWinsInfo;
+extern PEPROCESS NbtFspProcess;
+#endif
+extern tLMHOST_QUERIES LmHostQueries; // defined in parse.c
+extern ULONG NbtMemoryAllocated;
+
+#ifdef VXD
+extern ULONG DefaultDisconnectTimeout;
+#else
+extern LARGE_INTEGER DefaultDisconnectTimeout;
+#endif
+// ************** REMOVE LATER********************
+extern BOOLEAN StreamsStack;
+
+//#if DBG
+extern LIST_ENTRY UsedTrackers;
+extern LIST_ENTRY UsedIrps;
+//#endif
+#endif
+
+
diff --git a/private/ntos/nbt/inc/vxddebug.h b/private/ntos/nbt/inc/vxddebug.h
new file mode 100644
index 000000000..c81e76965
--- /dev/null
+++ b/private/ntos/nbt/inc/vxddebug.h
@@ -0,0 +1,150 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1993 **/
+/**********************************************************************/
+
+/*
+ debug.h
+
+ This file contains a number of debug-dependent definitions.
+
+
+ FILE HISTORY:
+ KeithMo 20-Sep-1993 Created.
+
+*/
+
+
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+
+
+#ifdef DEBUG
+
+#include <stdarg.h>
+
+#define DBG_MEMALLOC_VERIFY 0x0BEEFCAFE
+
+typedef struct {
+ LIST_ENTRY Linkage; // to keep linked list of allocated blocks
+ DWORD Verify; // our signature
+ DWORD ReqSize; // original size as requested by caller
+ DWORD Owner[4]; // stack trace 4 deep (of ret.addrs)
+} DbgMemBlkHdr;
+
+LIST_ENTRY DbgMemList;
+ULONG DbgLeakCheck;
+
+//
+// Debug output control flags.
+//
+
+extern DWORD VxdDebugFlags;
+
+
+#define VXD_DEBUG_INIT 0x00000001L
+#define VXD_DEBUG_SOCKET 0x00000002L
+#define VXD_DEBUG_MISC 0x00000004L
+#define VXD_DEBUG_BIND 0x00000008L
+#define VXD_DEBUG_ACCEPT 0x00000010L
+#define VXD_DEBUG_CONNECT 0x00000020L
+#define VXD_DEBUG_LISTEN 0x00000040L
+#define VXD_DEBUG_RECV 0x00000080L
+#define VXD_DEBUG_SEND 0x00000100L
+#define VXD_DEBUG_SOCKOPT 0x00000200L
+#define VXD_DEBUG_CONFIG 0x00000400L
+#define VXD_DEBUG_CONNECT_EVENT 0x00000800L
+#define VXD_DEBUG_DISCONNECT_EVENT 0x00001000L
+#define VXD_DEBUG_ERROR_EVENT 0x00002000L
+#define VXD_DEBUG_RECV_EVENT 0x00004000L
+#define VXD_DEBUG_RECV_DATAGRAM_EVENT 0x00008000L
+#define VXD_DEBUG_RECV_EXPEDITED_EVENT 0x00010000L
+// #define VXD_DEBUG_ 0x00020000L
+// #define VXD_DEBUG_ 0x00040000L
+// #define VXD_DEBUG_ 0x00080000L
+// #define VXD_DEBUG_ 0x00100000L
+// #define VXD_DEBUG_ 0x00200000L
+// #define VXD_DEBUG_ 0x00400000L
+// #define VXD_DEBUG_ 0x00800000L
+// #define VXD_DEBUG_ 0x01000000L
+// #define VXD_DEBUG_ 0x02000000L
+// #define VXD_DEBUG_ 0x04000000L
+// #define VXD_DEBUG_ 0x08000000L
+// #define VXD_DEBUG_ 0x10000000L
+// #define VXD_DEBUG_ 0x20000000L
+// #define VXD_DEBUG_ 0x40000000L
+#define VXD_DEBUG_OUTPUT_TO_DEBUGGER 0x80000000L
+
+//
+// Debug output function.
+//
+
+void VxdPrintf( char * pszFormat,
+ ... );
+
+int VxdSprintf( char * pszStr,
+ char * pszFmt,
+ ... );
+
+#define VXD_PRINT(args) VxdPrintf args
+
+
+//
+// Assert & require.
+//
+
+void VxdAssert( void * pAssertion,
+ void * pFileName,
+ unsigned long nLineNumber );
+
+#define VXD_ASSERT(exp) if (!(exp)) VxdAssert( #exp, __FILE__, __LINE__ )
+#define VXD_REQUIRE VXD_ASSERT
+
+
+//
+// Miscellaneous goodies.
+//
+
+void VxdDebugOutput( char * pszMessage );
+
+#define DEBUG_BREAK _asm int 3
+#define DEBUG_OUTPUT(x) VxdDebugOutput(x)
+
+
+#else // !DEBUG
+
+
+//
+// No debug output.
+//
+
+#define IF_DEBUG(flag) if (0)
+
+
+//
+// Null debug output function.
+//
+
+#define VXD_PRINT(args)
+
+
+//
+// Null assert & require.
+//
+
+#define VXD_ASSERT(exp)
+#define VXD_REQUIRE(exp) ((void)(exp))
+
+
+//
+// No goodies.
+//
+
+#define DEBUG_BREAK
+#define DEBUG_OUTPUT(x)
+
+
+#endif // DEBUG
+
+
+#endif // _DEBUG_H_
diff --git a/private/ntos/nbt/inc/vxdprocs.h b/private/ntos/nbt/inc/vxdprocs.h
new file mode 100644
index 000000000..b24946af6
--- /dev/null
+++ b/private/ntos/nbt/inc/vxdprocs.h
@@ -0,0 +1,1121 @@
+/**********************************************************************/
+/** Microsoft Windows/NT **/
+/** Copyright(c) Microsoft Corp., 1993 **/
+/**********************************************************************/
+
+/*
+ vxdprocs.h
+
+ This file contains VxD specific types/manifests for the NBT driver
+
+
+ FILE HISTORY:
+ Johnl 29-Mar-1993 Created
+
+*/
+
+#ifndef _VXDPROCS_H_
+#define _VXDPROCS_H_
+
+//--------------------------------------------------------------------
+//
+// Define some ndis stuff here because tdivxd.h needs it however we can't
+// include ndis3\inc\ndis.h because it conflicts with ntconfig.h and we
+// can't take out ntconfig.h because it has definitions needed by other
+// header files...grrrr....
+//
+
+#ifdef CHICAGO
+#ifndef NDIS_STDCALL
+#define NDIS_STDCALL 1
+#endif
+#include <vmm.h>
+#undef PAGE
+#define PAGE _PTEXT
+#endif
+
+#ifdef NDIS_STDCALL
+#define NDIS_API __stdcall
+#else
+#define NDIS_API
+#endif
+
+//
+// Ndis Buffer
+//
+
+#define BUFFER_POOL_SIGN (UINT)0X4C50424E /* NBPL */
+#define BUFFER_SIGN (UINT)0x4655424e /* NBUF */
+
+typedef INT NDIS_SPIN_LOCK, * PNDIS_SPIN_LOCK;
+
+struct _NDIS_BUFFER;
+typedef struct _NDIS_BUFFER_POOL {
+ UINT Signature; //character signature for debug "NBPL"
+ NDIS_SPIN_LOCK SpinLock; //to serialize access to the buffer pool
+ struct _NDIS_BUFFER *FreeList; //linked list of free slots in pool
+ UINT BufferLength; //amount needed for each buffer descriptor
+ UCHAR Buffer[1]; //actual pool memory
+ } NDIS_BUFFER_POOL, * PNDIS_BUFFER_POOL;
+
+#ifdef NDIS_STDCALL
+typedef struct _NDIS_BUFFER {
+ struct _NDIS_BUFFER *Next; //pointer to next buffer descriptor in chain
+ PVOID VirtualAddress; //linear address of this buffer
+ PNDIS_BUFFER_POOL Pool; //pointer to pool so we can free to correct pool
+ UINT Length; //length of this buffer
+ UINT Signature; //character signature for debug "NBUF"
+} NDIS_BUFFER, * PNDIS_BUFFER;
+
+#else
+
+typedef struct _NDIS_BUFFER {
+ UINT Signature; //character signature for debug "NBUF"
+ struct _NDIS_BUFFER *Next; //pointer to next buffer descriptor in chain
+ PVOID VirtualAddress; //linear address of this buffer
+ PNDIS_BUFFER_POOL Pool; //pointer to pool so we can free to correct pool
+ UINT Length; //length of this buffer
+} NDIS_BUFFER, * PNDIS_BUFFER;
+#endif
+
+#define NDIS_STATUS_SUCCESS 0 // Used by CTEinitBlockStruc macro
+
+//
+// Possible data types
+//
+
+typedef enum _NDIS_PARAMETER_TYPE {
+ NdisParameterInteger,
+ NdisParameterHexInteger,
+ NdisParameterString,
+ NdisParameterMultiString
+} NDIS_PARAMETER_TYPE, *PNDIS_PARAMETER_TYPE;
+
+typedef struct _STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PUCHAR Buffer;
+} STRING, *PSTRING;
+
+typedef STRING NDIS_STRING, *PNDIS_STRING;
+typedef PVOID NDIS_HANDLE, *PNDIS_HANDLE;
+
+//
+// To store configuration information
+//
+typedef struct _NDIS_CONFIGURATION_PARAMETER {
+ NDIS_PARAMETER_TYPE ParameterType;
+ union {
+ ULONG IntegerData;
+ NDIS_STRING StringData;
+ } ParameterData;
+} NDIS_CONFIGURATION_PARAMETER, *PNDIS_CONFIGURATION_PARAMETER;
+
+typedef ULONG NDIS_STATUS;
+typedef NDIS_STATUS *PNDIS_STATUS;
+
+VOID NDIS_API
+NdisOpenProtocolConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING ProtocolName
+ );
+
+VOID NDIS_API
+NdisReadConfiguration(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_CONFIGURATION_PARAMETER *ParameterValue,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PNDIS_STRING Parameter,
+ IN NDIS_PARAMETER_TYPE ParameterType
+ );
+
+VOID NDIS_API
+NdisCloseConfiguration(
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+//--------------------------------------------------------------------
+
+#include <tdivxd.h>
+#include <tdistat.h>
+
+//--------------------------------------------------------------------
+//
+// Initializes a TA_NETBIOS_ADDRESS structure
+//
+// ptanb - Pointer to the TA_NETBIOS_ADDRESS
+// pName - Pointer to the netbios name this address structure represents
+//
+#define InitNBAddress( ptanb, pName ) \
+{ \
+ (ptanb)->TAAddressCount = 1 ; \
+ (ptanb)->Address[0].AddressLength = sizeof( TDI_ADDRESS_NETBIOS );\
+ (ptanb)->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS ; \
+ (ptanb)->Address[0].Address[0].NetbiosNameType = 0 ; \
+ CTEMemCopy( (ptanb)->Address[0].Address[0].NetbiosName, \
+ pName, \
+ NCBNAMSZ ) ; \
+}
+
+//
+// Initializes a TDI_CONNECTION_INFORMATION structure for Netbios
+//
+// pConnInfo - Pointer to TDI_CONNECTION_INFORMATION structure
+// ptanb - same as for InitNBAddress
+// pName - same as for InitNBAddress
+//
+#define InitNBTDIConnectInfo( pConnInfo, ptanb, pName ) \
+{ \
+ InitNBAddress( ((PTA_NETBIOS_ADDRESS)ptanb), (pName) ) ; \
+ (pConnInfo)->RemoteAddressLength = sizeof( TA_NETBIOS_ADDRESS ) ; \
+ (pConnInfo)->RemoteAddress = (ptanb) ; \
+}
+
+//
+// Initializes an NDIS buffer (doesn't allocate memory)
+//
+// pndisBuff - Pointer to NDIS buffer to initialize
+// pvData - Pointer to buffer data
+// cbLen - Length of user data (in bytes)
+// pndisBuffnext - Next NDIS buffer in chain (or NULL if last)
+//
+#define InitNDISBuff( pndisBuff, pvData, cbLen, pndisBuffNext ) \
+{ \
+ (pndisBuff)->Signature = BUFFER_SIGN ; \
+ (pndisBuff)->Next = (pndisBuffNext) ; \
+ (pndisBuff)->Length = (cbLen) ; \
+ (pndisBuff)->VirtualAddress = (pvData) ; \
+ (pndisBuff)->Pool = NULL ; \
+}
+
+//
+// Proper NCB error type
+//
+typedef uchar NCBERR ;
+
+//
+// This is a private NCB command used for adding name number 0 to the
+// name table. It is submitted directly by the Nbt driver during
+// initialization. Note that if a client tries to submit an NCB with
+// this command we'll return illegal command.
+//
+#define NCBADD_PERMANENT_NAME 0xff
+
+//
+// Last valid NCB session or name number
+//
+#define MAX_NCB_NUMS 254
+
+//
+// When a send or receive tick count reaches this value, it's timed out
+//
+#define NCB_TIMED_OUT 1
+
+//
+// A timeout of this value means the NCB will never timeout
+//
+#define NCB_INFINITE_TIME_OUT 0
+
+//--------------------------------------------------------------------
+//
+// Receieve session data context, set in VxdReceive.
+// Allocated on the heap (too big for ncb_reserve).
+//
+#define RCVCONT_SIGN 0x1900BEEF
+typedef struct _RCV_CONTEXT
+{
+ union
+ {
+ LIST_ENTRY ListEntry ; // Used when NCB is put on RcvHead
+ EventRcvBuffer evrcvbuf ; // Used for doing actual receive
+ // (after removed from RcvHead)
+ } ;
+ UINT Signature ;
+ tLOWERCONNECTION * pLowerConnId ; // Where data is arriving from
+ NCB * pNCB ; // Pointer to NCB
+ NDIS_BUFFER ndisBuff ; // Transport fills this buffer
+ UCHAR RTO ; // 1/2 second ticks till timeout
+ USHORT usFlags; // in case different from default
+} RCV_CONTEXT, *PRCV_CONTEXT ;
+
+//
+// Allocate, initialize and free a receive context structure
+//
+#define GetRcvContext( ppContext ) \
+ (STATUS_SUCCESS == NbtGetBuffer( &NbtConfig.RcvContextFreeList, \
+ (PLIST_ENTRY*)ppContext, \
+ eNBT_RCV_CONTEXT ))
+
+#define FreeRcvContext( pRcvContext ) \
+{ \
+ ASSERT( (pRcvContext)->Signature == RCVCONT_SIGN ) ; \
+ InsertTailList( &NbtConfig.RcvContextFreeList, \
+ &(pRcvContext)->ListEntry ) ; \
+}
+
+#define InitRcvContext( pRcvCont, pRcvLowerConn, pRcvNCB ) \
+{ \
+ pRcvCont->Signature = RCVCONT_SIGN ; \
+ pRcvCont->pLowerConnId= pRcvLowerConn ; \
+ pRcvCont->pNCB = pRcvNCB ; \
+}
+
+//--------------------------------------------------------------------
+//
+// Send session data context, set in VxdSend.
+// Stored in ncb_reserve
+//
+typedef struct _SEND_CONTEXT
+{
+ LIST_ENTRY ListEntry ; // Kept on timeout queue
+ tSESSIONHDR * pHdr ; // Allocated session header
+ UCHAR STO ; // 1/2 second ticks till timeout
+} SEND_CONTEXT, *PSEND_CONTEXT ;
+
+
+#define GetSessionHdr( ppHdr ) \
+ (STATUS_SUCCESS == NbtGetBuffer( &NbtConfig.SessionBufferFreeList, \
+ (PLIST_ENTRY*)ppHdr, \
+ eNBT_SESSION_HDR ))
+
+#define FreeSessionHdr( pSessionHdr ) \
+{ \
+ InsertTailList( &NbtConfig.SessionBufferFreeList, \
+ (PLIST_ENTRY) pSessionHdr ) ; \
+}
+
+//--------------------------------------------------------------------
+//
+// TDI Send context (used by TdiSend)
+//
+// When handling the datagram completion routines, we need to set up
+// another completion routine. We store the old completion routine
+// in this structure
+//
+typedef union _TDI_SEND_CONTEXT
+{
+ LIST_ENTRY ListEntry ; // Only used when on buffer free list
+
+ struct
+ {
+ PVOID NewContext ;
+ NBT_COMPLETION OldRequestNotifyObject ;
+ PVOID OldContext ;
+ NDIS_BUFFER ndisHdr ; // Generally NBT message
+ NDIS_BUFFER ndisData1 ; // Data or SMB
+ NDIS_BUFFER ndisData2 ; // Data if ndisData1 is an SMB
+ } ;
+} TDI_SEND_CONTEXT, * PTDI_SEND_CONTEXT ;
+
+//
+// Allocates a TDI_SEND_CONTEXT
+//
+#define GetSendContext( ppContext ) \
+ (STATUS_SUCCESS == NbtGetBuffer( &NbtConfig.SendContextFreeList, \
+ (PLIST_ENTRY*)ppContext, \
+ eNBT_SEND_CONTEXT ))
+
+//
+// Frees a send context structure and its allocated memory
+//
+#define FreeSendContext( psendCont ) \
+{ \
+ InsertTailList( &NbtConfig.SendContextFreeList, \
+ &(psendCont)->ListEntry ) ; \
+}
+
+//--------------------------------------------------------------------
+//
+// Lana related stuff
+//
+
+#define NBT_MAX_LANAS 8
+
+typedef struct
+{
+ tDEVICECONTEXT * pDeviceContext ; // Adapter for this Lana
+} LANA_ENTRY, *PLANA_ENTRY ;
+
+extern LANA_ENTRY LanaTable[NBT_MAX_LANAS] ;
+
+//--------------------------------------------------------------------
+//
+// Procedures in ncb.c
+//
+//
+NCBERR MapTDIStatus2NCBErr( TDI_STATUS status ) ;
+
+//
+// Get the correct adapter for this NCBs Lana
+//
+tDEVICECONTEXT *
+GetDeviceContext(
+ NCB * pNCB
+ );
+
+BOOL
+NbtWouldLoopback(
+ ULONG IpAddr
+ );
+
+extern BOOL fNCBCompleted ; // Wait NCB completed before returning to submitter
+extern BOOL fWaitingForNCB ; // We are blocked waiting for a Wait NCB to complete
+extern CTEBlockStruc WaitNCBBlock ; // Wait on this until signaled in completion
+extern UCHAR LanaBase ;
+
+#define IPINFO_BUFF_SIZE (sizeof(IPInfo) + MAX_IP_NETS * sizeof(NetInfo))
+
+//--------------------------------------------------------------------
+//
+// externs from fileio.c
+//
+extern PUCHAR pFileBuff;
+extern PUCHAR pFilePath;
+
+//--------------------------------------------------------------------
+//
+// TDI Dispatch table (exported from vtdi.386)
+//
+extern TDIDispatchTable * TdiDispatch ;
+
+//
+// Wrappers for interfacing to the TDI Dispatch table
+//
+#define TdiVxdOpenAddress TdiDispatch->TdiOpenAddressEntry
+#define TdiVxdCloseAddress TdiDispatch->TdiCloseAddressEntry
+#define TdiVxdOpenConnection TdiDispatch->TdiOpenConnectionEntry
+#define TdiVxdCloseConnection TdiDispatch->TdiCloseConnectionEntry
+#define TdiVxdAssociateAddress TdiDispatch->TdiAssociateAddressEntry
+#define TdiVxdDisAssociateAddress TdiDispatch->TdiDisAssociateAddressEntry
+#define TdiVxdConnect TdiDispatch->TdiConnectEntry
+#define TdiVxdDisconnect TdiDispatch->TdiDisconnectEntry
+#define TdiVxdListen TdiDispatch->TdiListenEntry
+#define TdiVxdAccept TdiDispatch->TdiAcceptEntry
+#define TdiVxdReceive TdiDispatch->TdiReceiveEntry
+#define TdiVxdSend TdiDispatch->TdiSendEntry
+#define TdiVxdSendDatagram TdiDispatch->TdiSendDatagramEntry
+#define TdiVxdReceiveDatagram TdiDispatch->TdiReceiveDatagramEntry
+#define TdiVxdSetEventHandler TdiDispatch->TdiSetEventEntry
+#define TdiVxdQueryInformationEx TdiDispatch->TdiQueryInformationExEntry
+#define TdiVxdSetInformationEx TdiDispatch->TdiSetInformationExEntry
+
+//--------------------------------------------------------------------
+//
+// NTSTATUS to TDI_STATUS mappings.
+//
+// Rather then convert from NTSTATUS to TDI_STATUS (then sometimes back to
+// NTSTATUS) we'll just use TDI_STATUS codes everywhere (and map to NCBERR
+// when returning codes to the Netbios interface).
+//
+#undef STATUS_SUCCESS
+#undef STATUS_INSUFFICIENT_RESOURCES
+#undef STATUS_ADDRESS_ALREADY_EXISTS
+#undef STATUS_TOO_MANY_ADDRESSES
+#undef STATUS_INVALID_ADDRESS
+#undef STATUS_BUFFER_OVERFLOW
+#undef STATUS_TRANSACTION_INVALID_TYPE
+#undef STATUS_TRANSACTION_INVALID_ID
+#undef STATUS_EVENT_DONE
+#undef STATUS_TRANSACTION_TIMED_OUT
+#undef STATUS_EVENT_PENDING
+#undef STATUS_PENDING
+#undef STATUS_BAD_NETWORK_NAME
+#undef STATUS_REQUEST_NOT_ACCEPTED
+#undef STATUS_INVALID_CONNECTION
+#undef STATUS_DATA_NOT_ACCEPTED
+#undef STATUS_MORE_PROCESSING_REQUIRED
+#undef STATUS_IO_TIMEOUT
+#undef STATUS_TIMEOUT
+#undef STATUS_GRACEFUL_DISCONNECT
+#undef STATUS_CONNECTION_RESET
+
+#define STATUS_SUCCESS TDI_SUCCESS
+//#define STATUS_UNSUCCESSFUL
+#define STATUS_MORE_PROCESSING_REQUIRED TDI_MORE_PROCESSING
+#define STATUS_BAD_NETWORK_NAME TDI_INVALID_CONNECTION
+#define STATUS_DATA_NOT_ACCEPTED TDI_NOT_ACCEPTED
+//#define STATUS_REMOTE_NOT_LISTENING
+//#define STATUS_DUPLICATE_NAME
+//#define STATUS_INVALID_PARAMETER
+//#define STATUS_OBJECT_NAME_COLLISION Duplicate Name
+//#define STATUS_SHARING_VIOLATION Duplicate Name
+#define STATUS_CONNECTION_INVALID TDI_INVALID_CONNECTION
+#define STATUS_INVALID_CONNECTION TDI_INVALID_CONNECTION
+#define STATUS_INSUFFICIENT_RESOURCES TDI_NO_RESOURCES
+#define STATUS_ADDRESS_ALREADY_EXISTS TDI_ADDR_IN_USE
+#define STATUS_TOO_MANY_ADDRESSES TDI_NO_FREE_ADDR
+#define STATUS_INVALID_ADDRESS TDI_ADDR_INVALID
+#define STATUS_BUFFER_OVERFLOW TDI_BUFFER_OVERFLOW
+#define STATUS_TRANSACTION_INVALID_TYPE TDI_BAD_EVENT_TYPE
+#define STATUS_TRANSACTION_INVALID_ID TDI_BAD_OPTION // ??
+#define STATUS_EVENT_DONE TDI_EVENT_DONE
+#define STATUS_TRANSACTION_TIMED_OUT TDI_TIMED_OUT
+#define STATUS_IO_TIMEOUT TDI_TIMED_OUT
+#define STATUS_TIMEOUT TDI_TIMED_OUT
+#define STATUS_EVENT_PENDING TDI_PENDING
+#define STATUS_PENDING TDI_PENDING
+#define STATUS_GRACEFUL_DISCONNECT TDI_GRACEFUL_DISC
+#define STATUS_CONNECTION_RESET TDI_CONNECTION_RESET
+
+//
+// This is the "Name deregistered but not deleted because of
+// active sessions" error code.
+//
+#define STATUS_NRC_ACTSES 0xCA000001
+
+//
+// The NT_SUCCESS macro looks at the high bytes of the errr code which isn't
+// appropriate for our mapping to TDI_STATUS error codes
+//
+#undef NT_SUCCESS
+#define NT_SUCCESS(err) ((err==TDI_SUCCESS)||(err==TDI_PENDING))
+
+//--------------------------------------------------------------------
+//
+// General porting macros
+//
+//
+//--------------------------------------------------------------------
+
+//
+// Note that the ExInterlocked* routines (in ntos\ex\i386) do a spinlock
+// for MP machines. Since we aren't MP we shouldn't need the spin lock.
+// We shouldn't need to disable interrupts either.
+//
+#define ExInterlockedInsertTailList(list, entry, spinlock ) \
+ InsertTailList( (list), (entry) )
+
+#define ExInterlockedInsertHeadList(list, entry, spinlock ) \
+ InsertHeadList( (list), (entry) )
+
+//
+// These two definitions must be kept keep a couple of NT macros use
+// the ExInterlocked* macros
+//
+#ifdef InterlockedIncrement
+#undef InterlockedIncrement
+#endif
+#ifdef InterlockedIncrementLong
+#undef InterlockedIncrementLong
+#endif
+#define InterlockedIncrement(n) \
+ CTEInterlockedIncrementLong( n )
+#define InterlockedIncrementLong InterlockedIncrement
+
+#ifdef InterlockedDecrement
+#undef InterlockedDecrement
+#endif
+#ifdef InterlockedDecrementLong
+#undef InterlockedDecrementLong
+#endif
+#define InterlockedDecrement(n) \
+ CTEInterlockedDecrementLong( n )
+#define InterlockedDecrementLong InterlockedDecrement
+
+//--------------------------------------------------------------------
+//
+// Debug helper macros
+//
+#undef ASSERT
+#undef ASSERTMSG
+#ifdef DEBUG
+ #include <vxddebug.h>
+
+ extern DWORD DebugFlags ;
+ extern char DBOut[4096] ;
+ extern char szOutput[1024];
+ extern int iCurPos ;
+ void NbtDebugOut( char * ) ;
+
+ #define DBGFLAG_ALL (0x00000001) // Everything else
+ #define DBGFLAG_LMHOST (0x00000002)
+ #define DBGFLAG_KDPRINTS (0x00000004) // Jim's KdPrint output
+ #define DBGFLAG_ERROR (0x00000010)
+ #define DBGFLAG_AUX_OUTPUT (0x00000080)
+
+ #define DbgPrint( s ) \
+ if ( DebugFlags & DBGFLAG_ALL ) \
+ { \
+ VxdSprintf( szOutput, s ) ; \
+ VxdCopyToDBOut() ; \
+ NbtDebugOut( DBOut+iCurPos ) ; \
+ }
+
+ #define DbgPrintNum( n ) \
+ if ( DebugFlags & DBGFLAG_ALL ) \
+ { \
+ VxdSprintf( szOutput, "%x", n ) ; \
+ VxdCopyToDBOut() ; \
+ NbtDebugOut( DBOut+iCurPos ) ; \
+ }
+
+ #undef KdPrint
+ #define KdPrint( s ) \
+ if ( DebugFlags & DBGFLAG_KDPRINTS ) \
+ { \
+ VxdPrintf s ; \
+ }
+
+ //
+ // Conditional print routines
+ //
+ #define CDbgPrint( flag, s ) \
+ if ( DebugFlags & (flag) ) \
+ { \
+ VxdSprintf( szOutput, s ) ; \
+ VxdCopyToDBOut() ; \
+ NbtDebugOut( DBOut+iCurPos ) ; \
+ }
+
+ #define CDbgPrintNum( flag, n ) \
+ if ( DebugFlags & (flag) ) \
+ { \
+ VxdSprintf( szOutput, "%x", n ) ; \
+ VxdCopyToDBOut() ; \
+ NbtDebugOut( DBOut+iCurPos ) ; \
+ }
+
+ #define DbgBreak() _asm int 3
+ #define ASSERT( exp ) CTEAssert( exp )
+ #define ASSERTMSG( msg, exp ) CTEAssert( exp )
+ //
+ // REQUIRE is an ASSERT that keeps the expression under non-debug
+ // builds
+ //
+ #define REQUIRE( exp ) ASSERT( exp )
+
+ //
+ // Consistency checks of the interrupt vector table to help watch
+ // for NULL pointer writes
+ //
+ extern BYTE abVecTbl[256] ;
+ #define INIT_NULL_PTR_CHECK() memcpy( abVecTbl, 0, sizeof( abVecTbl ))
+ #define CHECK_MEM() if ( sizeof(abVecTbl) != VxdRtlCompareMemory( 0, abVecTbl, sizeof(abVecTbl)) ) \
+ { \
+ DbgPrint("Vector table corrupt at " ) ; \
+ DbgPrintNum( VxdRtlCompareMemory( 0, abVecTbl, sizeof(abVecTbl) ) ) ;\
+ DbgPrint("\n\r") ; \
+ _asm int 3 \
+ } \
+ CTECheckMem(__FILE__) ;
+#else
+ #define DbgPrint( s )
+ #define DbgPrintNum( n )
+ #define DbgBreak()
+ #undef KdPrint
+ #define KdPrint( s )
+ #define ASSERT( exp ) { ; }
+ #define ASSERTMSG( msg, exp ) { ; }
+ #define REQUIRE( exp ) { exp ; }
+ #define INIT_NULL_PTR_CHECK()
+ #define CHECK_MEM()
+ #define CDbgPrint( flag, s )
+ #define CDbgPrintNum( flag, n )
+#endif
+
+//---------------------------------------------------------------------
+//
+// FROM tdihndlr.c
+//
+TDI_STATUS
+TdiReceiveHandler (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID Data,
+ EventRcvBuffer * pevrcvbuf
+ );
+
+TDI_STATUS
+ReceiveAnyHandler ( // Handles NCBRCVANY commands, is
+ IN PVOID ReceiveEventContext, // called after all other receive
+ IN PVOID ConnectionContext, // handlers
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID Data,
+ PVOID * ppBuffer // Pointer to ListEntry of RCV_CONTEXT
+ ) ;
+
+TDI_STATUS
+VxdDisconnectHandler ( // Cleans up Netbios stuff for remote
+ IN PVOID DisconnectEventContext, // disconnects
+ IN PVOID ConnectionContext,
+ IN PVOID DisconnectData,
+ IN ULONG DisconnectInformationLength,
+ IN PVOID pDisconnectInformation,
+ IN ULONG DisconnectIndicators
+ ) ;
+
+VOID
+CompletionRcv(
+ IN PVOID pContext,
+ IN uint tdistatus,
+ IN uint BytesRcvd
+ );
+
+TDI_STATUS
+TdiConnectHandler (
+ IN PVOID pConnectEventContext,
+ IN int RemoteAddressLength,
+ IN PVOID pRemoteAddress,
+ IN int UserDataLength,
+ IN PVOID pUserData,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN PVOID * pAcceptingID,
+ IN ConnectEventInfo * pEventInfo
+ );
+
+TDI_STATUS
+TdiDisconnectHandler (
+ PVOID EventContext,
+ PVOID ConnectionContext,
+ ULONG DisconnectDataLength,
+ PVOID DisconnectData,
+ ULONG DisconnectInformationLength,
+ PVOID DisconnectInformation,
+ ULONG DisconnectIndicators // Is this the Flags field?
+ );
+
+TDI_STATUS
+TdiRcvDatagramHandler(
+ IN PVOID pDgramEventContext,
+ IN int SourceAddressLength,
+ IN PVOID pSourceAddress,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN UINT ReceiveDatagramFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *pBytesTaken,
+ IN PVOID pTsdu,
+ OUT EventRcvBuffer * * ppBuffer //OUT PIRP *pIoRequestPacket
+ );
+TDI_STATUS
+TdiRcvNameSrvHandler(
+ IN PVOID pDgramEventContext,
+ IN int SourceAddressLength,
+ IN PVOID pSourceAddress,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN UINT ReceiveDatagramFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *pBytesTaken,
+ IN PVOID pTsdu,
+ OUT EventRcvBuffer * * ppBuffer //OUT PIRP *pIoRequestPacket
+ );
+TDI_STATUS
+TdiErrorHandler (
+ IN PVOID Context,
+ IN ULONG Status
+ );
+
+VOID
+CompletionRcvDgram(
+ IN PVOID Context,
+ IN UINT tdistatus,
+ IN UINT RcvdSize
+ ) ;
+
+//---------------------------------------------------------------------
+//
+// FROM init.c
+//
+
+PVOID
+CTEAllocInitMem(
+ IN ULONG cbBuff ) ;
+
+NTSTATUS
+VxdReadIniString(
+ IN LPTSTR pchKeyName,
+ IN OUT LPTSTR * ppStringBuff
+ ) ;
+
+NTSTATUS CreateDeviceObject(
+ IN tNBTCONFIG *pConfig,
+ IN ULONG IpAddr,
+ IN ULONG IpMask,
+ IN ULONG IpNameServer,
+ IN ULONG IpBackupServer,
+ IN ULONG IpDnsServer,
+ IN ULONG IpDnsBackupServer,
+ IN UCHAR MacAddr[],
+ IN UCHAR IpIndex
+ ) ;
+
+void GetNameServerAddress( ULONG IpAddr,
+ PULONG pIpNameServer);
+
+void GetDnsServerAddress( ULONG IpAddr,
+ PULONG pIpNameServer);
+
+#define COUNT_NS_ADDR 4 // Maximum number of name server addresses
+//---------------------------------------------------------------------
+//
+// FROM vxdfile.asm
+//
+
+HANDLE
+VxdFileOpen(
+ IN char * pchFile ) ;
+
+ULONG
+VxdFileRead(
+ IN HANDLE hFile,
+ IN ULONG BytesToRead,
+ IN BYTE * pBuff ) ;
+
+VOID
+VxdFileClose(
+ IN HANDLE hFile ) ;
+
+PUCHAR
+VxdWindowsPath(
+ );
+
+//---------------------------------------------------------------------
+//
+// FROM vnbtd.asm
+//
+
+ULONG
+GetProfileHex(
+ IN HANDLE ParametersHandle, // Not used
+ IN PCHAR ValueName,
+ IN ULONG DefaultValue,
+ IN ULONG MinimumValue
+ );
+
+ULONG
+GetProfileInt(
+ IN HANDLE ParametersHandle, // Not used
+ IN PCHAR ValueName,
+ IN ULONG DefaultValue,
+ IN ULONG MinimumValue
+ );
+
+TDI_STATUS DhcpQueryInfo( UINT Type, PVOID pBuff, UINT * pSize ) ;
+
+//---------------------------------------------------------------------
+//
+// FROM tdiout.c
+//
+NTSTATUS VxdDisconnectWait( tLOWERCONNECTION * pLowerConn,
+ tDEVICECONTEXT * pDeviceContext,
+ ULONG Flags,
+ PVOID Timeout) ;
+
+NTSTATUS VxdScheduleDelayedCall( tDGRAM_SEND_TRACKING * pTracker,
+ PVOID pClientContext,
+ PVOID ClientCompletion,
+ PVOID CallBackRoutine,
+ tDEVICECONTEXT *pDeviceContext ) ;
+
+//---------------------------------------------------------------------
+//
+// FROM timer.c
+//
+BOOL CheckForTimedoutNCBs( CTEEvent *pEvent, PVOID pCont ) ;
+VOID StopTimeoutTimer( VOID );
+NTSTATUS StartRefreshTimer( VOID );
+
+//---------------------------------------------------------------------
+//
+// FROM tdicnct.c
+//
+NTSTATUS CloseAddress( HANDLE hAddress ) ;
+
+
+//---------------------------------------------------------------------
+//
+// FROM wfw.c - Snowball specific routines
+//
+#ifndef CHICAGO
+
+BOOL GetActiveLanasFromIP( VOID );
+
+#endif //!CHICAGO
+
+
+//---------------------------------------------------------------------
+//
+// FROM chic.c - Chicago specific routines
+//
+#ifdef CHICAGO
+
+NTSTATUS DestroyDeviceObject(
+ tNBTCONFIG *pConfig,
+ ULONG IpAddr
+ );
+
+BOOL IPRegisterAddrChangeHandler( PVOID AddChangeHandler, BOOL );
+
+TDI_STATUS IPNotification( ULONG IpAddress,
+ ULONG IpMask,
+ PVOID pDevNode,
+ USHORT IPContext,
+ BOOL fNew );
+
+BOOL VxdInitLmHostsSupport( PUCHAR pchLmHostPath, USHORT ulPathSize );
+
+VOID SaveNameDnsServerAddrs( VOID );
+BOOL VxdOpenNdis( VOID );
+VOID VxdCloseNdis( VOID );
+
+
+VOID ReleaseNbtConfigMem( VOID );
+
+NTSTATUS VxdUnload( LPSTR pchModuleName );
+
+#endif //CHICAGO
+
+//--------------------------------------------------------------------
+//
+// Procedures in vxdisol.c
+//
+//
+NCBERR VxdOpenName( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+NCBERR VxdCloseName( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+NCBERR VxdCall( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+NCBERR VxdListen( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+NCBERR VxdDgramSend( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+NCBERR VxdDgramReceive( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+NCBERR VxdReceiveAny( tDEVICECONTEXT *pDeviceContext, NCB * pNCB ) ;
+NCBERR VxdReceive( tDEVICECONTEXT * pDeviceContext, NCB * pNCB, BOOL fReceive ) ;
+NCBERR VxdHangup( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+NCBERR VxdCancel( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+NCBERR VxdSend( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+NCBERR VxdSessionStatus( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+VOID DelayedSessEstablish( PVOID pContext );
+
+
+//--------------------------------------------------------------------
+//
+// Procedures in dns.c
+//
+//
+PCHAR
+DnsStoreName(
+ OUT PCHAR pDest,
+ IN PCHAR pName,
+ IN PCHAR pDomainName,
+ IN enum eNSTYPE eNsType
+ );
+
+VOID
+DnsExtractName(
+ IN PCHAR pNameHdr,
+ IN LONG NumBytes,
+ OUT PCHAR pName,
+ OUT PULONG pNameSize
+ );
+
+VOID
+ProcessDnsResponse(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN USHORT OpCodeFlags
+ );
+
+VOID
+DnsCompletion(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+
+//
+// These routines all have "Direct" at the end of the routine name
+// because they are used exclusively for name queries to the DNS
+// server to resolve DNS names and not NetBIOS names.
+//
+
+VOID
+ProcessDnsResponseDirect(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN USHORT OpCodeFlags
+ );
+
+ULONG
+DoDnsResolveDirect(
+ PNCB pncb,
+ PUCHAR pzDnsName,
+ PULONG pIpAddressList
+ );
+
+BOOL
+DoDnsCancelDirect(
+ PNCB pncb
+ );
+
+VOID
+DnsCompletionDirect(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+
+PDNS_DIRECT_WORK_ITEM_CONTEXT
+FindContextDirect(
+ USHORT TransactionId
+ );
+
+VOID
+DnsActualCompletionDirect(
+ IN NBT_WORK_ITEM_CONTEXT * pnbtContext
+ );
+
+VOID
+DnsUnlinkAndCompleteDirect(
+ IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext
+ );
+
+NTSTATUS
+UdpSendDNSBcastDirect(
+ IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext,
+ IN ULONG Retries,
+ IN ULONG Timeout
+ );
+
+VOID
+SendDNSBcastDoneDirect(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo
+ );
+
+PDNS_DIRECT_SEND_CONTEXT
+CreateSendContextDirect(
+ IN PCHAR pName,
+ IN PCHAR pchDomainName,
+ OUT PVOID *pHdrs,
+ OUT PULONG pLength,
+ IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext
+ );
+
+VOID
+IpToAscii(
+ IN DWORD IpAddress,
+ IN OUT PCHAR pzAscii
+ );
+
+//
+// Flag passed to TdiSend indicating we are dealing with a chain send
+// and not a normal send.
+//
+#define CHAIN_SEND_FLAG 0x80
+typedef struct _tBUFFERCHAINSEND
+{
+ tBUFFER tBuff ; // Must be first member of this structure!!
+ PVOID pBuffer2 ;
+ ULONG Length2 ;
+} tBUFFERCHAINSEND ;
+
+
+//
+// Flag for pConnectEle->Flags indicating whether the client has been
+// notified the session is dead (by completing an NCB with NRC_SCLOSED)
+//
+#define NB_CLIENT_NOTIFIED 0x01
+
+
+//
+// Translates the name number/logical session number to the appropriate
+// structure pointer
+//
+NCBERR VxdFindClientElement( tDEVICECONTEXT * pDeviceContext,
+ UCHAR ncbnum,
+ tCLIENTELE * * ppClientEle,
+ enum CLIENT_TYPE Type ) ;
+NCBERR VxdFindConnectElement( tDEVICECONTEXT * pDeviceContext,
+ NCB * pNCB,
+ tCONNECTELE * * ppConnectEle ) ;
+NCBERR VxdFindLSN( tDEVICECONTEXT * pDeviceContext,
+ tCONNECTELE * pConnectEle,
+ UCHAR * plsn ) ;
+NCBERR VxdFindNameNum( tDEVICECONTEXT * pDeviceContext,
+ tADDRESSELE * pAddressEle,
+ UCHAR * pNum ) ;
+//
+// Used by Register/Unregister for selecting either the name table or the
+// session table from the device context
+//
+typedef enum
+{
+ NB_NAME,
+ NB_SESSION
+} NB_TABLE_TYPE ;
+
+BOOL NBRegister( tDEVICECONTEXT * pDeviceContext,
+ UCHAR * pNCBNum,
+ PVOID pElem,
+ NB_TABLE_TYPE NbTable ) ;
+BOOL NBUnregister( tDEVICECONTEXT * pDeviceContext,
+ UCHAR NCBNum,
+ NB_TABLE_TYPE NbTable ) ;
+
+TDI_STATUS VxdCompleteSessionNcbs( tDEVICECONTEXT * pDeviceContext,
+ tCONNECTELE * pConnEle ) ;
+
+NCBERR VxdCleanupAddress( tDEVICECONTEXT * pDeviceContext,
+ NCB * pNCB,
+ tCLIENTELE * pClientEle,
+ UCHAR NameNum,
+ BOOL fDeleteAddress ) ;
+
+BOOL ActiveSessions( tCLIENTELE * pClientEle ) ;
+
+//
+// This structure holds context information while we are waiting for
+// a session setup to complete (either listen or call)
+//
+// It is stored in the ncb_reserve field of the NCB
+//
+typedef struct _SESS_SETUP_CONTEXT
+{
+ TDI_CONNECTION_INFORMATION * pRequestConnect ; //
+ TDI_CONNECTION_INFORMATION * pReturnConnect ; // Name who answered the listen
+ tCONNECTELE * pConnEle ;
+ UCHAR fIsWorldListen ; // Listenning for '*'?
+} SESS_SETUP_CONTEXT, *PSESS_SETUP_CONTEXT ;
+
+
+void VxdTearDownSession( tDEVICECONTEXT * pDevCont,
+ tCONNECTELE * pConnEle,
+ PSESS_SETUP_CONTEXT pCont,
+ NCB * pNCB ) ;
+
+//
+// Finishes off a Netbios request (fill in NCB fields, call the post
+// routine etc.). Is macroed as CTEIoComplete.
+//
+VOID VxdIoComplete( PCTE_IRP pirp, NTSTATUS status, ULONG cbExtra ) ;
+
+ULONG
+_stdcall
+
+ VNBT_NCB_X( PNCB pNCB,
+ PUCHAR pzDnsName,
+ PULONG pIpAddress,
+ PVOID pExtended,
+ ULONG fFlag ) ;
+
+ULONG
+_stdcall
+VNBT_LANA_MASK(
+ );
+
+#endif //_VXDPROCS_H_
diff --git a/private/ntos/nbt/makefile.16 b/private/ntos/nbt/makefile.16
new file mode 100644
index 000000000..7171ec9a6
--- /dev/null
+++ b/private/ntos/nbt/makefile.16
@@ -0,0 +1,67 @@
+#
+#
+# Note: Currently the VXD can only be built on an NT machine in a Razzle
+# screen group. Building from DOS is not currently supported (requires
+# NT tree and NT environment variables). You must also be enlisted and
+# up to date in nt\private\inc, nt\private\ntos\inc, nt\private\ntos\nbt\*
+# and have the nt\public tree.
+#
+#
+# Steps to build the NBT VXD:
+#
+# 1) Ask GregJ for access to \\flipper\wb
+# 2) Copy/Enlist \\flipper\wb\src\common to your local machine
+# 3) Copy/Enlist \\flipper\wb\src\import\c8386
+# \sdk
+# \win32
+# \masm6
+# \wininc
+# \wintools
+# 4) Copy/Enlist \\flipper\wb\src\ndis3 to your local machine (needed
+# to build the TCP tree)
+# 5) Enlist in the tcp project on \\peanut\rhino
+# 6) Modify nbt\setenv.bat to setup the appropriate environment variables
+#
+# 7) Build the TCP driver (or at least tcp\vtdi which will build cxport.obj)
+# 8) Type "nmake -f makefile.16" in nbt
+# Note that if you get "out of far heapspace" when attempting to
+# compile nbt\vxd, cd to vxd and type nmake there (out of space
+# due to too much spawning).
+#
+# 9) The debug vnbtd.{sys, sym} will be in vxd\debug and the nondebug
+# version in vxd\nodebug.
+#
+
+!ifndef IMPORT
+!error *** You must first modify and run nbt\setenv.bat before building ***
+!endif
+
+all:
+ cd nbt
+ nmake -f makefile.16
+ cd ..\vxd
+ nmake
+
+nbt:
+ cd nbt
+ nmake -f makefile.16
+ cd ..\vxd
+ nmake
+
+debug:
+ cd nbt
+ nmake -f makefile.16 debug
+ cd ..\vxd
+ nmake debug
+
+depend:
+ cd nbt
+ nmake -f makefile.16 depend
+ cd ..\vxd
+ nmake depend
+
+clean:
+ cd nbt
+ nmake -f makefile.16 clean
+ cd ..\vxd
+ nmake clean
diff --git a/private/ntos/nbt/nbt/depend.mk b/private/ntos/nbt/nbt/depend.mk
new file mode 100644
index 000000000..4a3b35b67
--- /dev/null
+++ b/private/ntos/nbt/nbt/depend.mk
@@ -0,0 +1,391 @@
+$(NBTOBJD)/hashtbl.obj $(NBTDOBJD)/hashtbl.obj $(NBTSRC)/hashtbl.lst: \
+ $(NBTSRC)/hashtbl.c ../../$(INC)/sockets/netinet/in.h \
+ ../../$(INC)/status.h ../../$(INC)/sys/snet/ip_proto.h \
+ ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/dbgk.h ../$(INC)/ex.h ../$(INC)/exboosts.h \
+ ../$(INC)/exlevels.h ../$(INC)/hal.h ../$(INC)/i386.h \
+ ../$(INC)/init.h ../$(INC)/kd.h ../$(INC)/ke.h ../$(INC)/lfs.h \
+ ../$(INC)/lpc.h ../$(INC)/mips.h ../$(INC)/mm.h ../$(INC)/ntmp.h \
+ ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h ../$(INC)/ps.h \
+ ../$(INC)/se.h ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/nbtmsg.h \
+ $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h \
+ $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(IMPORT)/win32/ddk/inc/debug.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/io.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h $(BASEDIR)/tcp/h/cxport.h \
+ $(BASEDIR)/tcp/h/nettypes.h $(BASEDIR)/tcp/h/oscfg.h $(BASEDIR)/tcp/h/packoff.h \
+ $(BASEDIR)/tcp/h/packon.h $(BASEDIR)/tcp/h/tdi.h $(BASEDIR)/tcp/h/tdikrnl.h \
+ $(BASEDIR)/tcp/h/tdistat.h $(BASEDIR)/tcp/h/tdivxd.h
+
+$(NBTOBJD)/hndlrs.obj $(NBTDOBJD)/hndlrs.obj $(NBTSRC)/hndlrs.lst: \
+ $(NBTSRC)/hndlrs.c ../../$(INC)/sockets/netinet/in.h \
+ ../../$(INC)/status.h ../../$(INC)/sys/snet/ip_proto.h \
+ ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/dbgk.h ../$(INC)/ex.h ../$(INC)/exboosts.h \
+ ../$(INC)/exlevels.h ../$(INC)/hal.h ../$(INC)/i386.h \
+ ../$(INC)/init.h ../$(INC)/kd.h ../$(INC)/ke.h ../$(INC)/lfs.h \
+ ../$(INC)/lpc.h ../$(INC)/mips.h ../$(INC)/mm.h ../$(INC)/ntmp.h \
+ ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h ../$(INC)/ps.h \
+ ../$(INC)/se.h ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/nbtmsg.h \
+ $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h \
+ $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(IMPORT)/win32/ddk/inc/debug.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/io.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h $(BASEDIR)/tcp/h/cxport.h \
+ $(BASEDIR)/tcp/h/nettypes.h $(BASEDIR)/tcp/h/oscfg.h $(BASEDIR)/tcp/h/packoff.h \
+ $(BASEDIR)/tcp/h/packon.h $(BASEDIR)/tcp/h/tdi.h $(BASEDIR)/tcp/h/tdikrnl.h \
+ $(BASEDIR)/tcp/h/tdistat.h $(BASEDIR)/tcp/h/tdivxd.h
+
+$(NBTOBJD)/inbound.obj $(NBTDOBJD)/inbound.obj $(NBTSRC)/inbound.lst: \
+ $(NBTSRC)/inbound.c ../../$(INC)/sockets/netinet/in.h \
+ ../../$(INC)/status.h ../../$(INC)/sys/snet/ip_proto.h \
+ ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/dbgk.h ../$(INC)/ex.h ../$(INC)/exboosts.h \
+ ../$(INC)/exlevels.h ../$(INC)/hal.h ../$(INC)/i386.h \
+ ../$(INC)/init.h ../$(INC)/kd.h ../$(INC)/ke.h ../$(INC)/lfs.h \
+ ../$(INC)/lpc.h ../$(INC)/mips.h ../$(INC)/mm.h ../$(INC)/ntmp.h \
+ ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h ../$(INC)/ps.h \
+ ../$(INC)/se.h ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/nbtmsg.h \
+ $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h \
+ $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(IMPORT)/win32/ddk/inc/debug.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/io.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h $(BASEDIR)/tcp/h/cxport.h \
+ $(BASEDIR)/tcp/h/nettypes.h $(BASEDIR)/tcp/h/oscfg.h $(BASEDIR)/tcp/h/packoff.h \
+ $(BASEDIR)/tcp/h/packon.h $(BASEDIR)/tcp/h/tdi.h $(BASEDIR)/tcp/h/tdikrnl.h \
+ $(BASEDIR)/tcp/h/tdistat.h $(BASEDIR)/tcp/h/tdivxd.h
+
+$(NBTOBJD)/init.obj $(NBTDOBJD)/init.obj $(NBTSRC)/init.lst: $(NBTSRC)/init.c \
+ ../../$(INC)/sockets/netinet/in.h ../../$(INC)/status.h \
+ ../../$(INC)/sys/snet/ip_proto.h ../$(INC)/alpha.h \
+ ../$(INC)/alpharef.h ../$(INC)/arc.h ../$(INC)/bugcodes.h \
+ ../$(INC)/cache.h ../$(INC)/cm.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/kd.h ../$(INC)/ke.h \
+ ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h ../$(INC)/mm.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/v86emul.h $(INC)/ctemacro.h \
+ $(INC)/nbtmsg.h $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h \
+ $(INC)/timer.h $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(IMPORT)/win32/ddk/inc/debug.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/io.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h $(BASEDIR)/tcp/h/cxport.h \
+ $(BASEDIR)/tcp/h/nettypes.h $(BASEDIR)/tcp/h/oscfg.h $(BASEDIR)/tcp/h/packoff.h \
+ $(BASEDIR)/tcp/h/packon.h $(BASEDIR)/tcp/h/tdi.h $(BASEDIR)/tcp/h/tdikrnl.h \
+ $(BASEDIR)/tcp/h/tdistat.h $(BASEDIR)/tcp/h/tdivxd.h
+
+$(NBTOBJD)/name.obj $(NBTDOBJD)/name.obj $(NBTSRC)/name.lst: $(NBTSRC)/name.c \
+ ../../$(INC)/sockets/netinet/in.h ../../$(INC)/status.h \
+ ../../$(INC)/sys/snet/ip_proto.h ../$(INC)/alpha.h \
+ ../$(INC)/alpharef.h ../$(INC)/arc.h ../$(INC)/bugcodes.h \
+ ../$(INC)/cache.h ../$(INC)/cm.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/kd.h ../$(INC)/ke.h \
+ ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h ../$(INC)/mm.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/v86emul.h $(INC)/ctemacro.h \
+ $(INC)/nbtmsg.h $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h \
+ $(INC)/timer.h $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(IMPORT)/win32/ddk/inc/debug.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/io.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h $(BASEDIR)/tcp/h/cxport.h \
+ $(BASEDIR)/tcp/h/nettypes.h $(BASEDIR)/tcp/h/oscfg.h $(BASEDIR)/tcp/h/packoff.h \
+ $(BASEDIR)/tcp/h/packon.h $(BASEDIR)/tcp/h/tdi.h $(BASEDIR)/tcp/h/tdikrnl.h \
+ $(BASEDIR)/tcp/h/tdistat.h $(BASEDIR)/tcp/h/tdivxd.h
+
+$(NBTOBJD)/namesrv.obj $(NBTDOBJD)/namesrv.obj $(NBTSRC)/namesrv.lst: \
+ $(NBTSRC)/namesrv.c ../../$(INC)/sockets/netinet/in.h \
+ ../../$(INC)/status.h ../../$(INC)/sys/snet/ip_proto.h \
+ ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/dbgk.h ../$(INC)/ex.h ../$(INC)/exboosts.h \
+ ../$(INC)/exlevels.h ../$(INC)/hal.h ../$(INC)/i386.h \
+ ../$(INC)/init.h ../$(INC)/kd.h ../$(INC)/ke.h ../$(INC)/lfs.h \
+ ../$(INC)/lpc.h ../$(INC)/mips.h ../$(INC)/mm.h ../$(INC)/ntmp.h \
+ ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h ../$(INC)/ps.h \
+ ../$(INC)/se.h ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/nbtmsg.h \
+ $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h \
+ $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(IMPORT)/win32/ddk/inc/debug.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/io.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h $(BASEDIR)/tcp/h/cxport.h \
+ $(BASEDIR)/tcp/h/nettypes.h $(BASEDIR)/tcp/h/oscfg.h $(BASEDIR)/tcp/h/packoff.h \
+ $(BASEDIR)/tcp/h/packon.h $(BASEDIR)/tcp/h/tdi.h $(BASEDIR)/tcp/h/tdikrnl.h \
+ $(BASEDIR)/tcp/h/tdistat.h $(BASEDIR)/tcp/h/tdivxd.h
+
+$(NBTOBJD)/nbtutils.obj $(NBTDOBJD)/nbtutils.obj $(NBTSRC)/nbtutils.lst: \
+ $(NBTSRC)/nbtutils.c ../../$(INC)/sockets/netinet/in.h \
+ ../../$(INC)/status.h ../../$(INC)/sys/snet/ip_proto.h \
+ ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/dbgk.h ../$(INC)/ex.h ../$(INC)/exboosts.h \
+ ../$(INC)/exlevels.h ../$(INC)/hal.h ../$(INC)/i386.h \
+ ../$(INC)/init.h ../$(INC)/kd.h ../$(INC)/ke.h ../$(INC)/lfs.h \
+ ../$(INC)/lpc.h ../$(INC)/mips.h ../$(INC)/mm.h ../$(INC)/ntmp.h \
+ ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h ../$(INC)/ps.h \
+ ../$(INC)/se.h ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/nbtmsg.h \
+ $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h \
+ $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(IMPORT)/win32/ddk/inc/debug.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/io.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h $(BASEDIR)/tcp/h/cxport.h \
+ $(BASEDIR)/tcp/h/nettypes.h $(BASEDIR)/tcp/h/oscfg.h $(BASEDIR)/tcp/h/packoff.h \
+ $(BASEDIR)/tcp/h/packon.h $(BASEDIR)/tcp/h/tdi.h $(BASEDIR)/tcp/h/tdikrnl.h \
+ $(BASEDIR)/tcp/h/tdistat.h $(BASEDIR)/tcp/h/tdivxd.h
+
+$(NBTOBJD)/parse.obj $(NBTDOBJD)/parse.obj $(NBTSRC)/parse.lst: $(NBTSRC)/parse.c \
+ ../../$(INC)/sockets/netinet/in.h ../../$(INC)/status.h \
+ ../../$(INC)/sys/snet/ip_proto.h ../$(INC)/alpha.h \
+ ../$(INC)/alpharef.h ../$(INC)/arc.h ../$(INC)/bugcodes.h \
+ ../$(INC)/cache.h ../$(INC)/cm.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/kd.h ../$(INC)/ke.h \
+ ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h ../$(INC)/mm.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/v86emul.h $(INC)/ctemacro.h \
+ $(INC)/hosts.h $(INC)/nbtmsg.h $(INC)/nbtnt.h $(INC)/nbtprocs.h \
+ $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h $(INC)/vxddebug.h \
+ $(INC)/vxdprocs.h $(IMPORT)/win32/ddk/inc/debug.h \
+ $(BASEDIR)/public/sdk/inc/alphaops.h $(BASEDIR)/public/sdk/inc/crt/ctype.h \
+ $(BASEDIR)/public/sdk/inc/crt/excpt.h $(BASEDIR)/public/sdk/inc/crt/io.h \
+ $(BASEDIR)/public/sdk/inc/crt/stdarg.h $(BASEDIR)/public/sdk/inc/crt/stddef.h \
+ $(BASEDIR)/public/sdk/inc/crt/string.h $(BASEDIR)/public/sdk/inc/devioctl.h \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/nt.h $(BASEDIR)/public/sdk/inc/ntalpha.h \
+ $(BASEDIR)/public/sdk/inc/ntconfig.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntpsapi.h \
+ $(BASEDIR)/public/sdk/inc/ntregapi.h $(BASEDIR)/public/sdk/inc/ntrtl.h \
+ $(BASEDIR)/public/sdk/inc/ntseapi.h $(BASEDIR)/public/sdk/inc/ntstatus.h \
+ $(BASEDIR)/public/sdk/inc/ntxcapi.h $(BASEDIR)/public/sdk/inc/windef.h \
+ $(BASEDIR)/public/sdk/inc/winerror.h $(BASEDIR)/public/sdk/inc/winnt.h \
+ $(BASEDIR)/tcp/h/cxport.h $(BASEDIR)/tcp/h/nettypes.h $(BASEDIR)/tcp/h/oscfg.h \
+ $(BASEDIR)/tcp/h/packoff.h $(BASEDIR)/tcp/h/packon.h $(BASEDIR)/tcp/h/tdi.h \
+ $(BASEDIR)/tcp/h/tdikrnl.h $(BASEDIR)/tcp/h/tdistat.h $(BASEDIR)/tcp/h/tdivxd.h
+
+$(NBTOBJD)/proxy.obj $(NBTDOBJD)/proxy.obj $(NBTSRC)/proxy.lst: $(NBTSRC)/proxy.c \
+ ../../$(INC)/sockets/netinet/in.h ../../$(INC)/status.h \
+ ../../$(INC)/sys/snet/ip_proto.h ../$(INC)/alpha.h \
+ ../$(INC)/alpharef.h ../$(INC)/arc.h ../$(INC)/bugcodes.h \
+ ../$(INC)/cache.h ../$(INC)/cm.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/kd.h ../$(INC)/ke.h \
+ ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h ../$(INC)/mm.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/v86emul.h $(INC)/ctemacro.h \
+ $(INC)/nbtmsg.h $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h \
+ $(INC)/timer.h $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(IMPORT)/win32/ddk/inc/debug.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/io.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h $(BASEDIR)/tcp/h/cxport.h \
+ $(BASEDIR)/tcp/h/nettypes.h $(BASEDIR)/tcp/h/oscfg.h $(BASEDIR)/tcp/h/packoff.h \
+ $(BASEDIR)/tcp/h/packon.h $(BASEDIR)/tcp/h/tdi.h $(BASEDIR)/tcp/h/tdikrnl.h \
+ $(BASEDIR)/tcp/h/tdistat.h $(BASEDIR)/tcp/h/tdivxd.h
+
+$(NBTOBJD)/timer.obj $(NBTDOBJD)/timer.obj $(NBTSRC)/timer.lst: $(NBTSRC)/timer.c \
+ ../../$(INC)/sockets/netinet/in.h ../../$(INC)/status.h \
+ ../../$(INC)/sys/snet/ip_proto.h ../$(INC)/alpha.h \
+ ../$(INC)/alpharef.h ../$(INC)/arc.h ../$(INC)/bugcodes.h \
+ ../$(INC)/cache.h ../$(INC)/cm.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/kd.h ../$(INC)/ke.h \
+ ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h ../$(INC)/mm.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/v86emul.h $(INC)/ctemacro.h \
+ $(INC)/nbtmsg.h $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h \
+ $(INC)/timer.h $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(IMPORT)/win32/ddk/inc/debug.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/io.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h $(BASEDIR)/tcp/h/cxport.h \
+ $(BASEDIR)/tcp/h/nettypes.h $(BASEDIR)/tcp/h/oscfg.h $(BASEDIR)/tcp/h/packoff.h \
+ $(BASEDIR)/tcp/h/packon.h $(BASEDIR)/tcp/h/tdi.h $(BASEDIR)/tcp/h/tdikrnl.h \
+ $(BASEDIR)/tcp/h/tdistat.h $(BASEDIR)/tcp/h/tdivxd.h
+
+$(NBTOBJD)/udpsend.obj $(NBTDOBJD)/udpsend.obj $(NBTSRC)/udpsend.lst: \
+ $(NBTSRC)/udpsend.c ../../$(INC)/sockets/netinet/in.h \
+ ../../$(INC)/status.h ../../$(INC)/sys/snet/ip_proto.h \
+ ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/dbgk.h ../$(INC)/ex.h ../$(INC)/exboosts.h \
+ ../$(INC)/exlevels.h ../$(INC)/hal.h ../$(INC)/i386.h \
+ ../$(INC)/init.h ../$(INC)/kd.h ../$(INC)/ke.h ../$(INC)/lfs.h \
+ ../$(INC)/lpc.h ../$(INC)/mips.h ../$(INC)/mm.h ../$(INC)/ntmp.h \
+ ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h ../$(INC)/ps.h \
+ ../$(INC)/se.h ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/nbtmsg.h \
+ $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h \
+ $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(IMPORT)/win32/ddk/inc/debug.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/io.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h $(BASEDIR)/tcp/h/cxport.h \
+ $(BASEDIR)/tcp/h/nettypes.h $(BASEDIR)/tcp/h/oscfg.h $(BASEDIR)/tcp/h/packoff.h \
+ $(BASEDIR)/tcp/h/packon.h $(BASEDIR)/tcp/h/tdi.h $(BASEDIR)/tcp/h/tdikrnl.h \
+ $(BASEDIR)/tcp/h/tdistat.h $(BASEDIR)/tcp/h/tdivxd.h
+
diff --git a/private/ntos/nbt/nbt/dirs b/private/ntos/nbt/nbt/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/nbt/nbt/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/nbt/nbt/hashtbl.c b/private/ntos/nbt/nbt/hashtbl.c
new file mode 100644
index 000000000..c2ef4625f
--- /dev/null
+++ b/private/ntos/nbt/nbt/hashtbl.c
@@ -0,0 +1,668 @@
+//
+//
+// hashtbl.c
+//
+// This file contains the name code to implement the local and remote
+// hash tables used to store local and remote names to IP addresses
+// The hash table should not use more than 256 buckets since the hash
+// index is only calculated to one byte!
+
+#include "nbtprocs.h"
+
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(INIT, CreateHashTable)
+#pragma CTEMakePageable(INIT, InitRemoteHashTable)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+CreateHashTable(
+ tHASHTABLE **pHashTable,
+ LONG lNumBuckets,
+ enum eNbtLocation LocalRemote
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a hash table uTableSize long.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ ULONG uSize;
+ LONG i;
+ NTSTATUS status;
+
+ CTEPagedCode();
+
+ uSize = (lNumBuckets-1)*sizeof(LIST_ENTRY) + sizeof(tHASHTABLE);
+
+ *pHashTable = (tHASHTABLE *)CTEAllocInitMem(uSize);
+
+ if (*pHashTable)
+ {
+ CTEInitLock(&(*pHashTable)->SpinLock);
+
+ // initialize all of the buckets to have null chains off of them
+ for (i=0;i < lNumBuckets ;i++ )
+ {
+ InitializeListHead(&(*pHashTable)->Bucket[i]);
+ }
+
+ (*pHashTable)->LocalRemote = LocalRemote;
+ (*pHashTable)->lNumBuckets = lNumBuckets;
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_HASHTBL)
+ KdPrint(("NBT:Unable to create hash table\n"));
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ return(status);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+InitRemoteHashTable(
+ IN tNBTCONFIG *pConfig,
+ IN LONG NumBuckets,
+ IN LONG NumNames
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a linked list of buffers to use to store remote
+ names in the remote hash table. These are names that the proxy node
+ will answer for.
+
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not - failure means no response to net
+
+--*/
+{
+ NTSTATUS status;
+
+ CTEPagedCode();
+ status = CreateHashTable(&pConfig->pRemoteHashTbl,
+ NumBuckets,
+ NBT_REMOTE);
+
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+AddNotFoundToHashTable(
+ IN tHASHTABLE *pHashTable,
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN ULONG IpAddress,
+ IN enum eNbtAddrType NameType,
+ OUT tNAMEADDR **ppNameAddress
+ )
+/*++
+
+Routine Description:
+
+ This routine adds a name to IPaddress to the hash table
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+
+ status = FindInHashTable(pHashTable,pName,pScope,ppNameAddress);
+
+ if (status == STATUS_SUCCESS)
+ {
+ // found it in the table so we're done - return pending to
+ // differentiate from the name added case. Pending passes the
+ // NT_SUCCESS() test as well as Success does.
+ //
+ return(STATUS_PENDING);
+ }
+
+ //
+ //... otherwise add the new entry to the table
+ //
+ status = AddToHashTable(
+ pHashTable,
+ pName,
+ pScope,
+ IpAddress,
+ NameType,
+ NULL,
+ ppNameAddress);
+
+ return(status);
+
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+AddRecordToHashTable(
+ IN tNAMEADDR *pNameAddr,
+ IN PCHAR pScope
+ )
+/*++
+
+Routine Description:
+
+ This routine adds a nameaddr record to the hash table.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ tNAMEADDR *pNameAddress;
+
+ status = FindInHashTable(NbtConfig.pRemoteHashTbl,
+ pNameAddr->Name,
+ pScope,
+ &pNameAddress);
+
+ if (status == STATUS_SUCCESS)
+ {
+ //
+ // just return since the name has already resolved
+ // but first add this adapter to the adapters resolving the name
+ //
+ if (pNameAddress->IpAddress == pNameAddr->IpAddress)
+ {
+ pNameAddress->AdapterMask |= pNameAddr->AdapterMask;
+ }
+ status = STATUS_UNSUCCESSFUL;
+
+ }
+ else
+ {
+
+ //
+ //... otherwise add the new entry to the table
+ //
+
+ status = AddToHashTable(
+ NbtConfig.pRemoteHashTbl,
+ pNameAddr->Name,
+ pScope,
+ 0,
+ 0,
+ pNameAddr,
+ &pNameAddress);
+ }
+
+
+ return(status);
+
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+AddToHashTable(
+ IN tHASHTABLE *pHashTable,
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN ULONG IpAddress,
+ IN enum eNbtAddrType NameType,
+ IN tNAMEADDR *pNameAddr,
+ OUT tNAMEADDR **ppNameAddress
+ )
+/*++
+
+Routine Description:
+
+ This routine adds a name to IPaddress to the hash table
+ Called with the spin lock HELD.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ tNAMEADDR *pNameAddress;
+ tNAMEADDR *pScopeAddr;
+ NTSTATUS status;
+ int iIndex;
+ CTELockHandle OldIrq;
+
+ // first hash the name to an index
+ // take the lower nibble of the first 2 characters.. mod table size
+ iIndex = ((pName[0] & 0x0F) << 4) + (pName[1] & 0x0F);
+ iIndex = iIndex % pHashTable->lNumBuckets;
+
+ CTESpinLock(&NbtConfig,OldIrq);
+
+ if (!pNameAddr)
+ {
+ //
+ // Allocate memory for another hash table entry
+ //
+ pNameAddress = (tNAMEADDR *)NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('0'));
+ if (pNameAddress)
+ {
+ CTEZeroMemory(pNameAddress,sizeof(tNAMEADDR));
+ pNameAddress->RefCount = 1;
+
+ if ((pHashTable->LocalRemote == NBT_LOCAL) ||
+ (pHashTable->LocalRemote == NBT_REMOTE_ALLOC_MEM))
+ {
+ pNameAddress->Verify = LOCAL_NAME;
+ }
+ else
+ {
+ pNameAddress->Verify = REMOTE_NAME;
+ }
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig,OldIrq);
+ NBT_PROXY_DBG(("AddToHashTable: MAJOR ERROR - OUT OF HASH TABLE ENTRIES -- should never happen\n"));
+
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+
+ // fill in the record with the name and IpAddress
+ pNameAddress->NameTypeState = (NameType == NBT_UNIQUE) ?
+ NAMETYPE_UNIQUE : NAMETYPE_GROUP;
+
+ // set the state here to pending(conflict), so that when we set the state to its
+ // correct state in the routine that calls this one, we can check this
+ // value to be sure an interrupt has not come in and removed this entry
+ // from the list.
+ pNameAddress->NameTypeState |= STATE_CONFLICT;
+ pNameAddress->IpAddress = IpAddress;
+
+ // fill in the name
+ CTEMemCopy(pNameAddress->Name,pName,(ULONG)NETBIOS_NAME_SIZE);
+
+ }
+ else
+ {
+ pNameAddress = pNameAddr;
+ }
+
+ pNameAddress->pTimer = NULL;
+ pNameAddress->TimeOutCount = NbtConfig.RemoteTimeoutCount;
+
+ // put on the head of the list in case the same name is in the table
+ // twice (where the second one is waiting for its reference count to
+ // go to zero, and will ultimately be removed, we want to find the new
+ // name on any query of the table
+ //
+ InsertHeadList(&pHashTable->Bucket[iIndex],&pNameAddress->Linkage);
+
+
+ // check for a scope too ( on non-local names only )
+ if ((pHashTable->LocalRemote != NBT_LOCAL) && (*pScope))
+ {
+ // we must have a scope
+ // see if the scope is already in the hash table and add if necessary
+ //
+ status = FindInHashTable(pHashTable,
+ pScope,
+ NULL,
+ &pScopeAddr);
+
+ if (!NT_SUCCESS(status))
+ {
+ PUCHAR Scope;
+ status = STATUS_SUCCESS;
+
+ // *TODO* - this check will not adequately protect against
+ // bad scopes passed in - i.e. we may run off into memory
+ // and get an access violation...however converttoascii should
+ // do the protection. For local names the scope should be
+ // ok since NBT read it from the registry and checked it first
+ //
+ iIndex = 0;
+ Scope = pScope;
+ while (*Scope && (iIndex <= 255))
+ {
+ iIndex++;
+ Scope++;
+ }
+
+ // the whole length must be 255 or less, so the scope can only be
+ // 255-16...
+ if (iIndex > (255 - NETBIOS_NAME_SIZE))
+ {
+ RemoveEntryList(&pNameAddress->Linkage);
+
+ CTEMemFree(pNameAddress);
+
+ CTESpinFree(&NbtConfig,OldIrq);
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ iIndex++; // to copy the null
+
+ //
+ // the scope is a variable length string, so allocate enough
+ // memory for the tNameAddr structure based on this string length
+ //
+ pScopeAddr = (tNAMEADDR *)NbtAllocMem((USHORT)(sizeof(tNAMEADDR)
+ + iIndex
+ - NETBIOS_NAME_SIZE),NBT_TAG('1'));
+ if ( !pScopeAddr )
+ {
+ RemoveEntryList(&pNameAddress->Linkage);
+
+ CTEMemFree( pNameAddress );
+ CTESpinFree(&NbtConfig,OldIrq);
+ return STATUS_INSUFFICIENT_RESOURCES ;
+ }
+
+
+ // copy the scope to the name field including the Null at the end.
+ // to the end of the name
+ CTEMemCopy(pScopeAddr->Name,pScope,iIndex);
+
+ // mark the entry as containing a scope name for cleanup later
+ pScopeAddr->NameTypeState = NAMETYPE_SCOPE | STATE_RESOLVED;
+
+ // keep the size of the name in the context value for easier name
+ // comparisons in FindInHashTable
+
+ pScopeAddr->RefCount = 2;
+ pScopeAddr->ScopeLength = (PVOID)iIndex;
+ pNameAddress->pScope = pScopeAddr;
+
+ // add the scope record to the hash table
+ iIndex = ((pScopeAddr->Name[0] & 0x0F) << 4) + (pScopeAddr->Name[1] & 0x0F);
+ iIndex = iIndex % pHashTable->lNumBuckets;
+ InsertTailList(&pHashTable->Bucket[iIndex],&pScopeAddr->Linkage);
+
+ }
+ else
+ {
+ // the scope is already in the hash table so link the name to the
+ // scope
+ pNameAddress->pScope = pScopeAddr;
+ }
+ }
+ else
+ pNameAddress->pScope = NULL; // no scope
+
+
+
+ // return the pointer to the hash table block
+ *ppNameAddress = pNameAddress;
+ CTESpinFree(&NbtConfig,OldIrq);
+ return(STATUS_SUCCESS);
+}
+
+#ifdef PROXY_NODE
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+DeleteFromHashTable(
+ tHASHTABLE *pHashTable,
+ PCHAR pName
+ )
+/*++
+
+Routine Description:
+
+ This routine deletes an entry from the table.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ tNAMEADDR *pNameAddr;
+
+ // Remember to delete any timer that may be associated with the
+ // hash table entry!! Check BnodeCompletion before deleting timers since
+ // it deletes the timer just after it calls this routine,... we don't
+ // want to do it twice.
+
+ status = FindInHashTable(pHashTable,pName,NULL,&pNameAddr);
+
+ if (NT_SUCCESS(status))
+ {
+
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= STATE_CONFLICT;
+ NbtDereferenceName(pNameAddr);
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+ChgStateOfScopedNameInHashTable(
+ tHASHTABLE *pHashTable,
+ PCHAR pName,
+ PCHAR pScope,
+ DWORD NewState
+ )
+/*++
+
+Routine Description:
+
+ This routine deletes an entry from the table.
+ Don't call this function for changing the state of an entry in the
+ local table since it references the entry after calling NbtDereferenceName
+ which deallocates a local name if the RefCount on it goes to 0. See
+ comment about NbtDereferenceName in the function below
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+Called By:
+
+ ProxyTimerCompletionFn in Proxy.c
+
+--*/
+{
+ NTSTATUS status;
+ tNAMEADDR *pNameAddr;
+
+ // Remember to delete any timer that may be associated with the
+ // hash table entry!! Check BnodeCompletion before deleting timers since
+ // it deletes the timer just after it calls this routine,... we don't
+ // want to do it twice.
+
+ status = FindInHashTable(pHashTable,pName,pScope,&pNameAddr);
+
+ if (NT_SUCCESS(status))
+ {
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= NewState;
+ if (NewState == STATE_RELEASED)
+ {
+ NbtDereferenceName(pNameAddr);
+ //
+ // Set the state here again since NbtDereference changes the
+ // state to 0 when NewState is RELEASED (FUTURES: change
+ // NbtDereferenceName)
+ //
+ pNameAddr->NameTypeState |= NewState;
+ }
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+}
+#endif
+//----------------------------------------------------------------------------
+ NTSTATUS
+FindInHashTable(
+ tHASHTABLE *pHashTable,
+ PCHAR pName,
+ PCHAR pScope,
+ tNAMEADDR **pNameAddress
+ )
+/*++
+
+Routine Description:
+
+ This routine checks if the name passed in matches a hash table entry.
+ Called with the spin lock HELD.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ PLIST_ENTRY pEntry;
+ PLIST_ENTRY pHead;
+ tNAMEADDR *pNameAddr;
+ int iIndex;
+ ULONG uNameSize;
+ PCHAR pScopeTbl;
+
+ // first hash the name to an index...
+ // take the lower nibble of the first 2 characters.. mod table size
+ //
+ iIndex = ((pName[0] & 0x0F) << 4) + (pName[1] & 0x0F);
+ iIndex = iIndex % pHashTable->lNumBuckets;
+
+
+ // check if the name is already in the table
+ pHead = &pHashTable->Bucket[iIndex];
+
+ pEntry = pHead;
+
+ // check each entry in the hash list...until the end of the list
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+
+ if (pNameAddr->NameTypeState & NAMETYPE_SCOPE)
+ {
+ // scope names are treated differently since they are not
+ // 16 bytes long... the length is stored separately.
+ uNameSize = (ULONG)pNameAddr->ScopeLength;
+ }
+ else
+ uNameSize = NETBIOS_NAME_SIZE;
+
+
+ if (CTEMemEqu((PVOID)pName, (PVOID)pNameAddr->Name, uNameSize))
+ {
+
+ // now check if the scopes match. Scopes are stored differently
+ // on the local and remote tables.
+ //
+ if (!pScope)
+ {
+ // passing in a Null scope means try to find the name without
+ // a worrying about a scope matching too...
+ *pNameAddress = pNameAddr;
+ return(STATUS_SUCCESS);
+ }
+ else
+ if (pHashTable == NbtConfig.pLocalHashTbl)
+ {
+ // In the local hash table case the scope is the same for all
+ // names on the node and it it stored in the NbtConfig structure.
+ pScopeTbl = NbtConfig.pScope;
+ uNameSize = NbtConfig.ScopeLength;
+
+ }
+ else
+ {
+ // Remote Hash table
+ //
+
+ // check for a null scope, since remote names with no scope
+ // are put into the hash table with pScope == NULL
+ if (pNameAddr->pScope == NULL)
+ {
+ // NULL scope, in table so check if passed in scope
+ // points to a null.
+ if (*pScope == '\0')
+ {
+ *pNameAddress = pNameAddr;
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ //
+ // Scope does not match. Continue
+ //
+ continue;
+ }
+
+ }
+ else
+ {
+ pScopeTbl = &pNameAddr->pScope->Name[0];
+ uNameSize = (ULONG)pNameAddr->pScope->ScopeLength;
+ }
+ }
+
+
+ if (CTEMemEqu((PVOID)pScope, (PVOID)pScopeTbl, uNameSize))
+ {
+ // the scopes match so return
+ *pNameAddress = pNameAddr;
+ return(STATUS_SUCCESS);
+ }
+
+
+ } // end of matching name found
+ }
+
+ return(STATUS_UNSUCCESSFUL);
+
+}
diff --git a/private/ntos/nbt/nbt/hndlrs.c b/private/ntos/nbt/nbt/hndlrs.c
new file mode 100644
index 000000000..677e297e7
--- /dev/null
+++ b/private/ntos/nbt/nbt/hndlrs.c
@@ -0,0 +1,4186 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Hndlrs.c
+
+Abstract:
+
+
+ This file contains the Non OS specific implementation of handlers that are
+ called for Connects,Receives, Disconnects, and Errors.
+
+ This file represents the TDI interface on the Bottom of NBT after it has
+ been decoded into procedure call symantics from the Irp symantics used by
+ NT.
+
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#ifdef VXD
+
+#define NTProcessAcceptIrp(pIrp, pConnectEle) \
+ STATUS_NOT_SUPPORTED
+
+#define NTIndicateSessionSetup(pLowerConn,status) \
+ DbgPrint("Skipping NTIndicateSessionSetup\n\r")
+
+#endif //VXD
+
+#include "nbtprocs.h"
+#include "ctemacro.h"
+
+__inline long
+myntohl(long x)
+{
+ return((((x) >> 24) & 0x000000FFL) |
+ (((x) >> 8) & 0x0000FF00L) |
+ (((x) << 8) & 0x00FF0000L));
+}
+
+VOID
+ClearConnStructures (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tCONNECTELE *pConnectEle
+ );
+
+NTSTATUS
+CompleteSessionSetup (
+ IN tCLIENTELE *pClientEle,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tCONNECTELE *pConnectEle,
+ IN PCTE_IRP pIrp,
+ IN CTELockHandle OldIrq
+ );
+
+NTSTATUS
+MakeRemoteAddressStructure(
+ IN PCHAR pHalfAsciiName,
+ IN PVOID pSourceAddr,
+ IN ULONG lMaxNameSize,
+ OUT PVOID *ppRemoteAddress,
+ OUT PULONG pRemoteAddressLength,
+ IN ULONG NumAddr
+ );
+
+VOID
+CleanupAfterDisconnect(
+ IN PVOID pContext
+ );
+
+VOID
+AddToRemoteHashTbl (
+ IN tDGRAMHDR UNALIGNED *pDgram,
+ IN ULONG BytesIndicated,
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+
+VOID
+DoNothingComplete (
+ IN PVOID pContext
+ );
+
+ VOID
+AllocLowerConn(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN BOOLEAN fSpecial
+ );
+
+ VOID
+DelayedAllocLowerConn(
+ IN PVOID pContext
+ );
+
+ VOID
+DelayedAllocLowerConnSpecial(
+ IN PVOID pContext
+ );
+
+VOID
+GetIrpIfNotCancelled2(
+ IN tCONNECTELE *pConnEle,
+ OUT PIRP *ppIrp
+ );
+
+#ifdef VXD
+//----------------------------------------------------------------------------
+
+NTSTATUS
+RcvHandlrNotOs (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID *pTsdu,
+ OUT PVOID *RcvBuffer
+
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive event indication handler.
+
+ It is called when an session packet arrives from the network, when the
+ session has already been established (NBT_SESSION_UP state). The routine
+ looks for a receive buffer first and failing that looks for a receive
+ indication handler to pass the message to.
+
+Arguments:
+
+ pClientEle - ptr to the connecition record for this session
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+
+ NTSTATUS status;
+ PLIST_ENTRY pRcv;
+ PVOID pRcvElement;
+ tCLIENTELE *pClientEle;
+ tSESSIONHDR UNALIGNED *pSessionHdr;
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnectEle;
+ CTELockHandle OldIrq;
+ PIRP pIrp;
+ ULONG ClientBytesTaken;
+ BOOLEAN DebugMore;
+ ULONG RemainingPdu;
+
+//********************************************************************
+//********************************************************************
+//
+// NOTE: A copy of this procedure is in Tdihndlr.c - it is inlined for
+// the NT case. Therefore, only change this procedure and then
+// copy the procedure body to Tdihndlr.c
+//
+//
+//********************************************************************
+//********************************************************************
+
+ // get the ptr to the lower connection, and from that get the ptr to the
+ // upper connection block
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+ pSessionHdr = (tSESSIONHDR UNALIGNED *)pTsdu;
+
+ //
+ // Session ** UP ** processing
+ //
+ *BytesTaken = 0;
+
+ pConnectEle = pLowerConn->pUpperConnection;
+
+ ASSERT(pConnectEle->pClientEle);
+
+ ASSERT(BytesIndicated >= sizeof(tSESSIONHDR));
+
+ // this routine can get called by the next part of a large pdu, so that
+ // we don't always started at the begining of a pdu. The Bytes Rcvd
+ // value is set to zero in CompletionRcv when a new pdu is expected
+ //
+ if (pConnectEle->BytesRcvd == 0)
+ {
+
+ if (pSessionHdr->Type == NBT_SESSION_MESSAGE)
+ {
+
+ //
+ // expecting the start of a new session Pkt, so get the length out
+ // of the pTsdu passed in
+ //
+ pConnectEle->TotalPcktLen = myntohl(pSessionHdr->UlongLength);
+
+ // remove the Session header by adjusting the data pointer
+ pTsdu = (PVOID)((PUCHAR)pTsdu + sizeof(tSESSIONHDR));
+
+ // shorten the number of bytes since we have stripped off the
+ // session header
+ BytesIndicated -= sizeof(tSESSIONHDR);
+ BytesAvailable -= sizeof(tSESSIONHDR);
+ *BytesTaken = sizeof(tSESSIONHDR);
+ }
+ //
+ // Session Keep Alive
+ //
+ else
+ if (pSessionHdr->Type == NBT_SESSION_KEEP_ALIVE)
+ {
+ // session keep alives are simply discarded, since the act of sending
+ // a keep alive indicates the session is still alive, otherwise the
+ // transport would report an error.
+
+ // tell the transport that we took the Pdu
+ *BytesTaken = sizeof(tSESSIONHDR);
+ return(STATUS_SUCCESS);
+
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Unexpected Session Pdu received: type = %X\n",
+ pSessionHdr->Type));
+
+ ASSERT(0);
+ *BytesTaken = BytesIndicated;
+ return(STATUS_SUCCESS);
+
+ }
+ }
+
+ //
+ // check if there are any receive buffers queued against this connection
+ //
+ if (!IsListEmpty(&pConnectEle->RcvHead))
+ {
+ // get the first buffer off the receive list
+ pRcv = RemoveHeadList(&pConnectEle->RcvHead);
+#ifndef VXD
+ pRcvElement = CONTAINING_RECORD(pRcv,IRP,Tail.Overlay.ListEntry);
+
+ // the cancel routine was set when this irp was posted to Nbt, so
+ // clear it now, since the irp is being passed to the transport
+ //
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine((PIRP)pRcvElement,NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+
+#else
+ pRcvElement = CONTAINING_RECORD(pRcv, RCV_CONTEXT, ListEntry ) ;
+#endif
+
+ //
+ // this buffer is actually an Irp, so pass it back to the transport
+ // as a return parameter
+ //
+ *RcvBuffer = pRcvElement;
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+ }
+
+ //
+ // No receives on this connection. Is there a receive event handler for this
+ // address?
+ //
+ pClientEle = pConnectEle->pClientEle;
+
+#ifdef VXD
+ //
+ // there is always a receive event handler in the Nt case - it may
+ // be the default handler, but it is there, so no need for test.
+ //
+ if (pClientEle->evReceive)
+#endif
+ {
+
+
+ // check that we have not received more data than we should for
+ // this session Pdu. i.e. part of the next session pdu. BytesRcvd may
+ // have a value other than zero if the pdu has arrived in two chunks
+ // and the client has taken the previous one in the indication rather
+ // than passing back an Irp.
+ //
+#if DBG
+ DebugMore = FALSE;
+#endif
+ RemainingPdu = pConnectEle->TotalPcktLen - pConnectEle->BytesRcvd;
+ if (BytesAvailable >= RemainingPdu)
+ {
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:More Data Recvd than expecting! Avail= %X,TotalLen= %X,state=%x\n",
+ BytesAvailable,pConnectEle->TotalPcktLen,pLowerConn->StateRcv));
+#if DBG
+ DebugMore =TRUE;
+#endif
+ // shorten the indication to the client so that they don't
+ // get more data than the end of the pdu
+ //
+ BytesAvailable = RemainingPdu;
+ if (BytesIndicated > BytesAvailable)
+ {
+ BytesIndicated = BytesAvailable;
+ }
+ //
+ // We always indicated at raised IRQL since we call freelockatdispatch
+ // below
+ //
+ ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE | TDI_RECEIVE_AT_DISPATCH_LEVEL;
+ }
+ else
+ {
+ // the transport may have has this flag on. We need to
+ // turn it off if the entire message is not present, where entire
+ // message means within the bytesAvailable length. We deliberately
+ // use bytesavailable so that Rdr/Srv can know that the next
+ // indication will be a new message if they set bytestaken to
+ // bytesavailable.
+ //
+ ReceiveFlags &= ~TDI_RECEIVE_ENTIRE_MESSAGE;
+ ReceiveFlags |= TDI_RECEIVE_AT_DISPATCH_LEVEL;
+#ifndef VXD
+ BytesAvailable = RemainingPdu;
+#endif
+ }
+
+ //
+ // NT-specific code locks pLowerConn before calling this routine,
+ //
+ CTESpinFreeAtDpc(pLowerConn);
+
+ // call the Client Event Handler
+ ClientBytesTaken = 0;
+ status = (*pClientEle->evReceive)(
+ pClientEle->RcvEvContext,
+ pConnectEle->ConnectContext,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ &ClientBytesTaken,
+ pTsdu,
+ &pIrp);
+
+ CTESpinLockAtDpc(pLowerConn);
+#if DBG
+ if (DebugMore)
+ {
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(( "Client TOOK %X bytes, pIrp = %X,status =%X\n",
+ ClientBytesTaken,pIrp,status));
+ }
+#endif
+ if (!pLowerConn->pUpperConnection)
+ {
+ // the connection was disconnected in the interim
+ // so do nothing.
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ CTEIoComplete(pIrp,STATUS_CANCELLED,0);
+ *BytesTaken = BytesAvailable;
+ return(STATUS_SUCCESS);
+ }
+ }
+ else
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ ASSERT(pIrp);
+ //
+ // the client may pass back a receive in the pIrp.
+ // In this case pIrp is a valid receive request Irp
+ // and the status is MORE_PROCESSING
+ //
+
+ // don't put these lines outside the if incase the client
+ // does not set ClientBytesTaken when it returns an error
+ // code... we don't want to use the value then
+ //
+ // count the bytes received so far. Most of the bytes
+ // will be received in the CompletionRcv handler in TdiHndlr.c
+ pConnectEle->BytesRcvd += ClientBytesTaken;
+
+ // The client has taken some of the data at least...
+ *BytesTaken += ClientBytesTaken;
+
+ *RcvBuffer = pIrp;
+
+ // ** FAST PATH **
+ return(status);
+ }
+ else
+ //
+ // no irp was returned... the client just took some of the bytes..
+ //
+ if (status == STATUS_SUCCESS)
+ {
+
+ // count the bytes received so far.
+ pConnectEle->BytesRcvd += ClientBytesTaken;
+ *BytesTaken += ClientBytesTaken;
+
+ //
+ // look at how much data was taken and adjust some counts
+ //
+ if (pConnectEle->BytesRcvd == pConnectEle->TotalPcktLen)
+ {
+ // ** FAST PATH **
+ CHECK_PTR(pConnectEle);
+ pConnectEle->BytesRcvd = 0; // reset for the next session pdu
+ return(status);
+ }
+ else
+ if (pConnectEle->BytesRcvd > pConnectEle->TotalPcktLen)
+ {
+ //IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Too Many Bytes Rcvd!! Rcvd# = %d, TotalLen = %d\n",
+ pConnectEle->BytesRcvd,pConnectEle->TotalPcktLen));
+
+ ASSERTMSG("Nbt:Client Took Too Much Data!!!\n",0);
+
+ //
+ // try to recover by saying that the client took all of the
+ // data so at least the transport is not confused too
+ //
+ *BytesTaken = BytesIndicated;
+
+ }
+ else
+ // the client did not take all of the data so
+ // keep track of the fact
+ {
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("NBT:Client took Indication BytesRcvd=%X, TotalLen=%X BytesAvail %X ClientTaken %X\n",
+ pConnectEle->BytesRcvd,
+ pConnectEle->TotalPcktLen,
+ BytesAvailable,
+ ClientBytesTaken));
+
+ //
+ // the next time the client sends down a receive buffer
+ // the code will pass it to the transport and decrement the
+ // ReceiveIndicated counter which is set in Tdihndlr.c
+
+ }
+ }
+ else
+ if (status == STATUS_DATA_NOT_ACCEPTED)
+ {
+ // client has not taken ANY data...
+ //
+ // In this case the *BytesTaken is set to 4, the session hdr.
+ // since we really have taken that data to setup the PduSize
+ // in the pConnEle structure.
+ //
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("NBT: Status DATA NOT ACCEPTED returned from client Avail %X %X\n",
+ BytesAvailable,pConnectEle));
+
+ // the code in tdihndlr.c normally looks after incrementing
+ // the ReceiveIndicated count for data that is not taken by
+ // the client, but if it is a zero length send that code cannot
+ // detect it, so we put code here to handle that case
+ //
+ // It is possible for the client to do a disconnect after
+ // we release the spin lock on pLowerConn to call the Client's
+ // disconnect indication. If that occurs, do not overwrite
+ // the StateProc with PartialRcv
+ //
+ if ((pConnectEle->TotalPcktLen == 0) &&
+ (pConnectEle->state == NBT_SESSION_UP))
+ {
+ pLowerConn->StateRcv = PARTIAL_RCV;
+ SetStateProc( pLowerConn, PartialRcv ) ;
+ CHECK_PTR(pConnectEle);
+ pConnectEle->ReceiveIndicated = 0; // zero bytes waiting for client
+ }
+ else
+ {
+ //
+ // if any bytes were taken (i.e. the session hdr) then
+ // return status success. (otherwise the status is
+ // statusNotAccpeted).
+ //
+ if (*BytesTaken)
+ {
+ status = STATUS_SUCCESS;
+ }
+ }
+
+ //
+ // the next time the client sends down a receive buffer
+ // the code will pass it to the transport and decrement this
+ // counter.
+ }
+ else
+ ASSERT(0);
+
+
+ return(status);
+
+ }
+#ifdef VXD
+ //
+ // there is always a receive event handler in the Nt case - it may
+ // be the default handler, but it is there, so no need for test.
+ //
+ else
+ {
+ //
+ // there is no client buffer to pass the data to, so keep
+ // track of the fact so when the next client buffer comes down
+ // we can get the data from the transport.
+ //
+ KdPrint(("NBT:Client did not have a Buffer posted, rcvs indicated =%X,BytesRcvd=%X, TotalLen=%X\n",
+ pConnectEle->ReceiveIndicated,
+ pConnectEle->BytesRcvd,
+ pConnectEle->TotalPcktLen));
+
+ // the routine calling this one increments ReceiveIndicated and sets the
+ // state to PartialRcv to keep track of the fact that there is data
+ // waiting in the transport
+ //
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+#endif
+}
+#endif // VXD case
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+Inbound (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PVOID *RcvBuffer
+
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to setup inbound session
+ once the tcp connection is up. The transport calls this routine with
+ a session setup request pdu.
+
+
+Arguments:
+
+ pClientEle - ptr to the connecition record for this session
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+
+ NTSTATUS status;
+ tCLIENTELE *pClientEle;
+ tSESSIONHDR UNALIGNED *pSessionHdr;
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnectEle;
+ CTELockHandle OldIrq;
+ PIRP pIrp;
+ PLIST_ENTRY pEntry;
+ CONNECTION_CONTEXT ConnectId;
+ PTA_NETBIOS_ADDRESS pRemoteAddress;
+ ULONG RemoteAddressLength;
+
+ // get the ptr to the lower connection
+ //
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+ pSessionHdr = (tSESSIONHDR UNALIGNED *)pTsdu;
+
+ //
+ // fake out the transport so it frees its receive buffer (i.e. we
+ // say that we accepted all of the data)
+ //
+ *BytesTaken = BytesIndicated;
+
+ pConnectEle = pLowerConn->pUpperConnection;
+
+ //
+ // since we send keep alives on connections in the the inbound
+ // state it is possible to get a keep alive, so just return in that
+ // case
+ //
+ if (((tSESSIONHDR UNALIGNED *)pTsdu)->Type == NBT_SESSION_KEEP_ALIVE)
+ {
+ return(STATUS_SUCCESS);
+ }
+
+ // the LowerConn Lock is held prior to calling this routine, so free it
+ // here since we need to get the joint lock first
+ CTESpinFreeAtDpc(pLowerConn);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CTESpinLockAtDpc(pLowerConn);
+
+ //
+ // Session ** INBOUND ** setup processing
+ //
+ ASSERT(pLowerConn->State == NBT_SESSION_INBOUND);
+ // it is possible for the disconnect handler to run while the pLowerConn
+ // lock is released above, to get the ConnEle lock, and change the state
+ // to disconnected.
+ if (pLowerConn->State != NBT_SESSION_INBOUND)
+ {
+ CTESpinFreeAtDpc(pLowerConn);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ goto ExitCode;
+ }
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt: In SessionSetupnotOS, connection state = %X\n",pLowerConn->State));
+
+
+ if (pSessionHdr->Type != NBT_SESSION_REQUEST)
+ {
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Unexpected Session Pdu received during setup: type = %X\n",
+ pSessionHdr->Type));
+
+ CTESpinFreeAtDpc(pLowerConn);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ RejectSession(pLowerConn,
+ NBT_NEGATIVE_SESSION_RESPONSE,
+ SESSION_UNSPECIFIED_ERROR,
+ TRUE);
+ goto ExitCode;
+ }
+ else
+ {
+ CTESpinFreeAtDpc(pLowerConn);
+ }
+
+ status = FindSessionEndPoint(pTsdu,
+ ConnectionContext,
+ BytesIndicated,
+ &pClientEle,
+ &pRemoteAddress,
+ &RemoteAddressLength);
+
+ if (status != STATUS_SUCCESS)
+ {
+
+ //
+ // could not find the desired end point so send a negative session
+ // response pdu and then disconnect
+ //
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ RejectSession(pLowerConn,
+ NBT_NEGATIVE_SESSION_RESPONSE,
+ status,
+ TRUE);
+
+ goto ExitCode;
+ }
+
+ //
+ // we must first check for a valid LISTEN....
+ //
+ CTESpinLockAtDpc(pClientEle);
+ if (!IsListEmpty(&pClientEle->ListenHead))
+ {
+ tLISTENREQUESTS *pListen;
+ tLISTENREQUESTS *pListenTarget ;
+
+ //
+ // Find the first listen that matches the remote name else
+ // take a listen that specified '*'
+ //
+ pListenTarget = NULL;
+ for ( pEntry = pClientEle->ListenHead.Flink ;
+ pEntry != &pClientEle->ListenHead ;
+ pEntry = pEntry->Flink )
+ {
+ pListen = CONTAINING_RECORD(pEntry,tLISTENREQUESTS,Linkage);
+
+ // in NT-land the pConnInfo structure is passed in , but the
+ // remote address field is nulled out... so we need to check
+ // both of these before going on to check the remote address.
+ if ( pListen->pConnInfo && pListen->pConnInfo->RemoteAddress)
+ {
+
+ if ( CTEMemEqu(
+ ((PTA_NETBIOS_ADDRESS)pListen->pConnInfo->RemoteAddress)->
+ Address[0].Address[0].NetbiosName,
+ pRemoteAddress->Address[0].Address[0].NetbiosName,
+ NETBIOS_NAME_SIZE ) )
+ {
+ pListenTarget = pListen ;
+ break ;
+ }
+ }
+ else
+ {
+ //
+ // Specified '*' for the remote name, save this,
+ // look for listen on a real name - only save if it is
+ // the first * listen found
+ //
+ if (!pListenTarget)
+ {
+ pListenTarget = pListen ;
+ }
+ }
+ }
+
+ if (pListenTarget)
+ {
+ PTA_NETBIOS_ADDRESS pRemoteAddr;
+
+ RemoveEntryList( &pListenTarget->Linkage );
+ CTESpinFreeAtDpc(pClientEle);
+
+ //
+ // Fill in the remote machines name to return to the client
+ //
+ if ((pListenTarget->pReturnConnInfo) &&
+ (pRemoteAddr = pListenTarget->pReturnConnInfo->RemoteAddress))
+ {
+ CTEMemCopy(pRemoteAddr,pRemoteAddress,RemoteAddressLength);
+ }
+
+ //
+ // get the upper connection end point out of the listen and
+ // hook the upper and lower connections together.
+ //
+ pConnectEle = (tCONNECTELE *)pListenTarget->pConnectEle;
+
+ CTESpinLockAtDpc(pConnectEle);
+ CTESpinLockAtDpc(pClientEle);
+
+ pConnectEle->pLowerConnId = (PVOID)pLowerConn;
+ pConnectEle->state = NBT_SESSION_WAITACCEPT;
+ CHECK_PTR(pConnectEle);
+ pConnectEle->pIrpRcv = NULL;
+
+ pLowerConn->pUpperConnection = pConnectEle;
+ pLowerConn->State = NBT_SESSION_WAITACCEPT;
+ pLowerConn->StateRcv = NORMAL;
+
+ CHECK_PTR(pConnectEle);
+ SetStateProc( pLowerConn, RejectAnyData ) ;
+
+ //
+ // put the upper connection on its active list
+ //
+ RemoveEntryList(&pConnectEle->Linkage);
+ InsertTailList(&pConnectEle->pClientEle->ConnectActive,&pConnectEle->Linkage);
+
+ //
+ // Save the remote name while we still have it
+ //
+ CTEMemCopy( pConnectEle->RemoteName,
+ pRemoteAddress->Address[0].Address[0].NetbiosName,
+ NETBIOS_NAME_SIZE ) ;
+
+ CTESpinFreeAtDpc(pClientEle);
+
+ if (!(pListenTarget->Flags & TDI_QUERY_ACCEPT))
+ {
+ //
+ // We need to send a session response PDU here, since
+ // we do not have to wait for an accept in this case
+ //
+ CompleteSessionSetup(pClientEle,
+ pLowerConn,pConnectEle,
+ pListenTarget->pIrp,
+ OldIrq);
+
+ }
+ else
+ {
+ //
+ // complete the client listen irp, which will trigger him to
+ // issue an accept, which should find the connection in the
+ // WAIT_ACCEPT state, and subsequently cause a session response
+ // to be sent.
+ //
+ // since the lower connection now points to pConnectEle, increment
+ // the reference count so we can't free pConnectEle memory until
+ // the lower conn no longer points to it.
+ pConnectEle->RefCount++;
+
+ ClearConnStructures(pLowerConn,pConnectEle);
+
+ CTESpinFreeAtDpc(pConnectEle);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+#ifndef VXD
+ // the irp can't get cancelled because the cancel listen routine
+ // also grabs the Client spin lock and removes the listen from the
+ // list..
+ CTEIoComplete( pListenTarget->pIrp,STATUS_SUCCESS,0);
+#else
+ CTEIoComplete( pListenTarget->pIrp,STATUS_SUCCESS, (ULONG) pConnectEle);
+#endif
+ }
+
+ CTEMemFree((PVOID)pRemoteAddress);
+ CTEMemFree(pListenTarget);
+
+ // now that we have notified the client, dereference it
+ //
+ NbtDereferenceClient(pClientEle);
+
+ PUSH_LOCATION(0x60);
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt: Accepted Connection by a Listen %X LowerConn=%X\n",pConnectEle,pLowerConn));
+
+ // fake out the transport so it frees its receive buffer (i.e. we
+ // say that we accepted all of the data)
+ *BytesTaken = BytesAvailable;
+ goto ExitCode;
+ }
+ else
+ CTESpinFreeAtDpc(pClientEle);
+
+ }
+ else
+ CTESpinFreeAtDpc(pClientEle);
+
+ //
+ // No LISTEN, so check for an Event handler
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ if (!pClientEle->ConEvContext)
+ {
+
+ RejectSession(pLowerConn,
+ NBT_NEGATIVE_SESSION_RESPONSE,
+ SESSION_NOT_LISTENING_ON_CALLED_NAME,
+ TRUE);
+
+ // undo the reference done in FindEndpoint
+ //
+ NbtDereferenceClient(pClientEle);
+
+ goto ExitCode;
+ }
+#ifdef VXD
+ else
+ {
+ ASSERT( FALSE ) ;
+ }
+#endif
+
+ // now call the client's connect handler...
+ pIrp = NULL;
+#ifndef VXD // VXD doesn't support event handlers
+
+ status = (*pClientEle->evConnect)(pClientEle->ConEvContext,
+ RemoteAddressLength,
+ pRemoteAddress,
+ 0,
+ NULL,
+ 0, // options length
+ NULL, // Options
+ &ConnectId,
+ &pIrp
+ );
+ //
+ // With the new TDI semantics is it illegal to return STATUS_EVENT_DONE
+ // or STATUS_EVENT_PENDING from the connect event handler
+ //
+ ASSERT(status != STATUS_EVENT_PENDING);
+ ASSERT(status != STATUS_EVENT_DONE);
+
+
+ // now that we have notified the client, dereference it
+ //
+ NbtDereferenceClient(pClientEle);
+
+ // Check the returned status codes..
+ if (status == STATUS_MORE_PROCESSING_REQUIRED && pIrp != NULL)
+ {
+ // connection is accepted
+ (VOID)NTProcessAcceptIrp(pIrp,&pConnectEle);
+
+ //
+ // Save the remote name while we still have it
+ //
+ CTEMemCopy( pConnectEle->RemoteName,
+ pRemoteAddress->Address[0].Address[0].NetbiosName,
+ NETBIOS_NAME_SIZE ) ;
+
+ // be sure the connection is in the correct state
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CTESpinLockAtDpc(pConnectEle);
+ if (pConnectEle->state != NBT_ASSOCIATED)
+ {
+ CTESpinFreeAtDpc(pConnectEle);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ goto RejectIt;
+ }
+ else
+ {
+ pConnectEle->state = NBT_SESSION_UP;
+
+ CHECK_PTR(pConnectEle);
+
+ CompleteSessionSetup(pClientEle,pLowerConn,pConnectEle,pIrp,OldIrq);
+
+ }
+
+ }
+ else
+ {
+RejectIt:
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:The client rejected in the inbound connection status = %X\n",
+ status));
+ RejectSession(pLowerConn,
+ NBT_NEGATIVE_SESSION_RESPONSE,
+ SESSION_CALLED_NAME_PRESENT_NO_RESRC,
+ TRUE);
+
+ }
+#endif
+ //
+ // free the memory allocated for the Remote address data structure
+ //
+ CTEMemFree((PVOID)pRemoteAddress);
+
+ExitCode:
+ // This spin lock is held by the routine that calls this one, and
+ // freed when this routine starts, so we must regrab this lock before
+ // returning
+ //
+ CTESpinLockAtDpc(pLowerConn);
+ return(STATUS_SUCCESS);
+}
+//----------------------------------------------------------------------------
+ VOID
+ClearConnStructures (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tCONNECTELE *pConnectEle
+ )
+/*++
+
+Routine Description:
+
+ This routine sets various parts of the connection datastructures to
+ zero, in preparation for a new connection.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+ CHECK_PTR(pConnectEle);
+#ifndef VXD
+ pConnectEle->FreeBytesInMdl = 0;
+ pConnectEle->CurrentRcvLen = 0;
+ pLowerConn->BytesInIndicate = 0;
+#endif
+ pConnectEle->ReceiveIndicated = 0;
+ pConnectEle->BytesInXport = 0;
+ pConnectEle->BytesRcvd = 0;
+ pConnectEle->TotalPcktLen = 0;
+ pConnectEle->OffsetFromStart = 0;
+ pConnectEle->pIrpRcv = NULL;
+ pConnectEle->pIrp = NULL;
+ pConnectEle->pIrpDisc = NULL;
+ pConnectEle->pIrpClose = NULL;
+ pConnectEle->DiscFlag = 0;
+ pConnectEle->JunkMsgFlag = FALSE;
+ pConnectEle->pLowerConnId = (PVOID)pLowerConn;
+ InitializeListHead(&pConnectEle->RcvHead);
+
+ pLowerConn->pUpperConnection = pConnectEle;
+ pLowerConn->StateRcv = NORMAL;
+
+ pLowerConn->BytesRcvd = 0;
+ pLowerConn->BytesSent = 0;
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+CompleteSessionSetup (
+ IN tCLIENTELE *pClientEle,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tCONNECTELE *pConnectEle,
+ IN PCTE_IRP pIrp,
+ IN CTELockHandle OldIrq
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to setup an outbound session
+ once the tcp connection is up. The transport calls this routine with
+ a session setup response pdu.
+
+ The pConnectEle spin lock is held when this routine is called.
+
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+
+ NTSTATUS status;
+
+ //
+ // hook the upper and lower connections together to
+ // complete the address list.
+ //
+ CTESpinLockAtDpc(pClientEle);
+
+ RemoveEntryList(&pConnectEle->Linkage);
+
+ ClearConnStructures(pLowerConn,pConnectEle);
+ pConnectEle->state = NBT_SESSION_UP;
+
+ pLowerConn->State = NBT_SESSION_UP;
+
+ SetStateProc( pLowerConn, Normal ) ;
+ PUSH_LOCATION(0x61);
+
+
+ InsertTailList(&pConnectEle->pClientEle->ConnectActive,
+ &pConnectEle->Linkage);
+
+
+ // since the lower connection now points to pConnectEle, increment
+ // the reference count so we can't free pConnectEle memory until
+ // the lower conn no longer points to it.
+ //
+ pConnectEle->RefCount++;
+ CTESpinFreeAtDpc(pClientEle);
+ //
+ // the pConnecteEle
+ if (OldIrq)
+ {
+ CTESpinFreeAtDpc(pConnectEle);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ status = TcpSendSessionResponse(pLowerConn,
+ NBT_POSITIVE_SESSION_RESPONSE,
+ 0L);
+
+ if (NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt: Accepted Connection %X LowerConn=%X\n",pConnectEle,pLowerConn));
+
+ //
+ // complete the client's accept Irp
+ //
+#ifndef VXD
+ CTEIoComplete(pIrp,STATUS_SUCCESS,0);
+#else
+ CTEIoComplete( pIrp,STATUS_SUCCESS, (ULONG) pConnectEle);
+#endif
+
+ }
+ else
+ { //
+ // if we have some trouble sending the Session response, then
+ // disconnect the connection
+ //
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Could not send the Session Response to TCP status = %X\n",
+ status));
+
+
+ RejectSession(pLowerConn,
+ NBT_NEGATIVE_SESSION_RESPONSE,
+ SESSION_CALLED_NAME_PRESENT_NO_RESRC,
+ TRUE);
+
+
+ RelistConnection(pConnectEle);
+
+ // Disconnect To Client - i.e. a negative Accept
+ // this will get done when the disconnect indication
+ // comes back from the transport
+ //
+ GetIrpIfNotCancelled(pConnectEle,&pIrp);
+ if (pIrp)
+ {
+ CTEIoComplete(pIrp,STATUS_UNSUCCESSFUL,0);
+ }
+ }
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+Outbound (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PVOID *RcvBuffer
+
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to setup an outbound session
+ once the tcp connection is up. The transport calls this routine with
+ a session setup response pdu .
+
+
+Arguments:
+
+ pClientEle - ptr to the connection record for this session
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+
+ tSESSIONHDR UNALIGNED *pSessionHdr;
+ tLOWERCONNECTION *pLowerConn;
+ CTELockHandle OldIrq;
+ PIRP pIrp;
+ tTIMERQENTRY *pTimerEntry;
+ tCONNECTELE *pConnEle;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tDEVICECONTEXT *pDeviceContext;
+ NTSTATUS status;
+
+ // get the ptr to the lower connection
+ //
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+ pSessionHdr = (tSESSIONHDR UNALIGNED *)pTsdu;
+ pDeviceContext = pLowerConn->pDeviceContext;
+
+ //
+ // fake out the transport so it frees its receive buffer (i.e. we
+ // say that we accepted all of the data)
+ //
+ *BytesTaken = BytesIndicated;
+ //
+ // since we send keep alives on connections in the the inbound
+ // state it is possible to get a keep alive, so just return in that
+ // case
+ //
+ if (((tSESSIONHDR UNALIGNED *)pTsdu)->Type == NBT_SESSION_KEEP_ALIVE)
+ {
+ return(STATUS_SUCCESS);
+ }
+
+ pConnEle = pLowerConn->pUpperConnection;
+
+ // the LowerConn Lock is held prior to calling this routine, so free it
+ // here since we need to get the joint lock first
+ CTESpinFreeAtDpc(pLowerConn);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CTESpinLockAtDpc(pLowerConn);
+
+ //
+ // it is possible for the disconnect handler to run while the pLowerConn
+ // lock is released above, to get the ConnEle lock, and change the state
+ // to disconnected.
+ //
+ if (!pConnEle || (pConnEle->state != NBT_SESSION_OUTBOUND))
+ {
+ CTESpinFreeAtDpc(pLowerConn);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ RejectSession(pLowerConn,0,0,FALSE);
+ goto ExitCode;
+ }
+
+ // NbtConnect stores the tracker in the IrpRcv ptr so that this
+ // routine can access it
+ //
+ pTracker = (tDGRAM_SEND_TRACKING *)pConnEle->pIrpRcv;
+ //
+ // if no tracker then SessionStartupCompletion has run and the connection
+ // is about to be closed, so return.
+ //
+ if (!pTracker)
+ {
+ CTESpinFreeAtDpc(pLowerConn);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ goto ExitCode;
+ }
+ CHECK_PTR(pConnEle);
+ pConnEle->pIrpRcv = NULL;
+
+ //
+ // Stop the timer started in SessionStartupCompletion to time the
+ // Session Setup Response message - it is possible for this routine to
+ // run before SessionStartupCompletion, in which case there will not be
+ // any timer to stop.
+ //
+ if (pTimerEntry = pTracker->Connect.pTimer)
+ {
+ StopTimer(pTimerEntry,NULL,NULL);
+ CHECK_PTR(pTracker);
+ pTracker->Connect.pTimer = NULL;
+ }
+
+ if (pSessionHdr->Type == NBT_POSITIVE_SESSION_RESPONSE)
+ {
+ // zero out the number of bytes received so far, since this is
+ // a new connection
+ CHECK_PTR(pConnEle);
+ pConnEle->BytesRcvd = 0;
+ pConnEle->state = NBT_SESSION_UP;
+
+ pLowerConn->State = NBT_SESSION_UP;
+ SetStateProc( pLowerConn, Normal ) ;
+
+ CTESpinFreeAtDpc(pLowerConn);
+
+ GetIrpIfNotCancelled2(pConnEle,&pIrp);
+
+ //
+ // if SessionSetupContinue has run, it has set the refcount to zero
+ //
+ if (pTracker->RefConn == 0)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
+ }
+ else
+ {
+ pTracker->RefConn--;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ CHECK_PTR(pLowerConn->pUpperConnection);
+ pLowerConn->pUpperConnection->pIrpRcv = NULL;
+
+ // the assumption is that if the connect irp was cancelled then the
+ // client should be doing a disconnect or close shortly thereafter, so
+ // there is no error handling code here.
+ if (pIrp)
+ {
+ //
+ // complete the client's connect request Irp
+ //
+#ifndef VXD
+ CTEIoComplete( pIrp, STATUS_SUCCESS, 0 ) ;
+#else
+ CTEIoComplete( pIrp, STATUS_SUCCESS, (ULONG)pConnEle ) ;
+#endif
+ }
+ }
+ else
+ {
+ ULONG ErrorCode;
+ ULONG state;
+ tNAMEADDR *pNameAddr;
+
+ state = pConnEle->state;
+
+ // If the response is Retarget then setup another session
+ // to the new Ip address and port number.
+ //
+ ErrorCode = (ULONG)((tSESSIONERROR *)pSessionHdr)->ErrorCode;
+ if (pSessionHdr->Type == NBT_RETARGET_SESSION_RESPONSE)
+ {
+ //
+ // retry the session setup if we haven't already exceeded the
+ // count
+ //
+ if (pConnEle->SessionSetupCount--)
+ {
+ PVOID Context=NULL;
+ BOOLEAN Cancelled;
+
+ pConnEle->state = NBT_ASSOCIATED;
+
+ // for retarget the destination has specified an alternate
+ // port to which the session should be established.
+ if (pSessionHdr->Type == NBT_RETARGET_SESSION_RESPONSE)
+ {
+ pTracker->DestPort = ntohs(((tSESSIONRETARGET *)pSessionHdr)->Port);
+ Context = (PVOID)ntohl(((tSESSIONRETARGET *)pSessionHdr)->IpAddress);
+ }
+ else
+ if (ErrorCode == SESSION_CALLED_NAME_NOT_PRESENT)
+ {
+ // to tell Reconnect to use the current name(not a retarget)
+ Context = NULL;
+ }
+
+ //
+ // Unlink the lower and upper connections.
+ //
+ CHECK_PTR(pConnEle);
+ CHECK_PTR(pLowerConn);
+ pLowerConn->pUpperConnection = NULL;
+ pConnEle->pLowerConnId = NULL;
+
+ CTESpinFreeAtDpc(pLowerConn);
+
+ //
+ // put the pconnele back on the Client's ConnectHead if it
+ // has not been cleanedup yet.
+ //
+ if (state != NBT_IDLE)
+ {
+ RelistConnection(pConnEle);
+ }
+
+ // if a disconnect comes down in this state we we will handle it.
+ pConnEle->state = NBT_RECONNECTING;
+
+ CHECK_PTR(pConnEle);
+ pConnEle->SessionSetupCount = 0;// only allow one retry
+
+ pIrp = pConnEle->pIrp;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // remove the referenced added when the lower and upper
+ // connections were attached in nbtconnect.
+ //
+ NbtDereferenceConnection(pConnEle);
+
+ RejectSession(pLowerConn,0,0,FALSE);
+ Cancelled = FALSE;
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Attempt Reconnect after receiving error on connect, error=%X LowerConn %X\n",
+ ErrorCode,pLowerConn));
+#ifndef VXD
+ // the irp can't be cancelled until the connection
+ // starts up again - either when the Irp is in the transport
+ // or when we set our cancel routine in SessionStartupCompletion
+ // This disconnect handler cannot complete the Irp because
+ // we set the pConnEle state to NBT_ASSOCIATED above, with
+ // the spin lock held, which prevents the Disconnect handler
+ // from doing anything.
+ IoAcquireCancelSpinLock(&OldIrq);
+ if (pIrp && !pConnEle->pIrp->Cancel)
+ {
+ IoSetCancelRoutine(pIrp,NULL);
+ }
+ else
+ Cancelled = TRUE;
+
+ IoReleaseCancelSpinLock(OldIrq);
+#endif
+
+ if (!Cancelled)
+ {
+ CTEQueueForNonDispProcessing(pTracker,
+ Context,
+ NULL,
+ ReConnect,
+ pDeviceContext);
+ }
+ // ...else The irp was already returned, since NtCancelSession
+ // Must have already run, so just return
+ goto ExitCode;
+ }
+ }
+
+ pNameAddr = pTracker->pNameAddr;
+ //
+ // if it is in the remote table and still active...
+ // and no one else is referencing the name, then delete it from
+ // the hash table.
+ //
+ if ((pNameAddr->Verify == REMOTE_NAME) &&
+ (pNameAddr->RefCount == 1) &&
+ (pNameAddr->NameTypeState & STATE_RESOLVED))
+ {
+ NbtDereferenceName(pNameAddr);
+ }
+
+ // the connection will be disconnected by the Call to RejectSession
+ // below, so set the state to Associated so the disconnect indication
+ // handler will not complete the client's irp too
+ //
+ pConnEle->state = NBT_ASSOCIATED;
+ CHECK_PTR(pConnEle);
+ pConnEle->pLowerConnId = NULL;
+
+ CTESpinFreeAtDpc(pLowerConn);
+
+ //
+ // if nbtcleanupconnection has not been called yet, relist it.
+ //
+ if (state != NBT_IDLE)
+ {
+ RelistConnection(pConnEle);
+ }
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Disconnecting... Failed connection Setup %X Lowercon %X\n",
+ pConnEle,pLowerConn));
+
+ GetIrpIfNotCancelled2(pConnEle,&pIrp);
+
+ //
+ // if SessionSetupContinue has run, it has set the refcount to zero
+ //
+ if (pTracker->RefConn == 0)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
+ }
+ else
+ {
+ pTracker->RefConn--;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ // this should cause a disconnect indication to come from the
+ // transport which will close the connection to the transport
+ //
+ RejectSession(pLowerConn,0,0,FALSE);
+
+ //
+ // tell the client that the session setup failed and disconnect
+ // the connection
+ //
+
+ if (pIrp)
+ {
+ status = STATUS_REMOTE_NOT_LISTENING;
+ if (ErrorCode == SESSION_CALLED_NAME_NOT_PRESENT)
+ {
+ status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ CTEIoComplete(pIrp, status, 0 ) ;
+ }
+ }
+
+ExitCode:
+ // the LowerConn Lock is held prior to calling this routine. It is freed
+ // at the start of this routine and held here again
+ CTESpinLockAtDpc(pLowerConn);
+
+ return(STATUS_SUCCESS);
+}
+//----------------------------------------------------------------------------
+ VOID
+GetIrpIfNotCancelled2(
+ IN tCONNECTELE *pConnEle,
+ OUT PIRP *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine coordinates access to the Irp by getting the spin lock on
+ the client, getting the Irp and clearing the irp in the structure. The
+ Irp cancel routines also check the pConnEle->pIrp and if null they do not
+ find the irp, then they return without completing the irp.
+
+ This version of the routine is called with NbtConfig.JointLock held.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(pConnEle,OldIrq);
+
+ *ppIrp = pConnEle->pIrp;
+ CHECK_PTR(pConnEle);
+ pConnEle->pIrp = NULL;
+
+ CTESpinFree(pConnEle,OldIrq);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+GetIrpIfNotCancelled(
+ IN tCONNECTELE *pConnEle,
+ OUT PIRP *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine coordinates access to the Irp by getting the spin lock on
+ the client, getting the Irp and clearing the irp in the structure. The
+ Irp cancel routines also check the pConnEle->pIrp and if null they do not
+ find the irp, then they return without completing the irp.
+
+ This version of the routine is called with NbtConfig.JointLock free.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ GetIrpIfNotCancelled2(pConnEle,ppIrp);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+RejectAnyData(
+ IN PVOID ReceiveEventContext,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PVOID *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive event indication handler when the connection
+ is not up - i.e. nbt thinks no data should be arriving. We just eat the
+ data and return. This routine should not get called.
+
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+
+ //
+ // take all of the data so that a disconnect will not be held up
+ // by data still in the transport.
+ //
+ *BytesTaken = BytesAvailable;
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Got Session Data in state %X, StateRcv= %X\n",pLowerConn->State,
+ pLowerConn->StateRcv));
+
+ return(STATUS_SUCCESS);
+}
+//----------------------------------------------------------------------------
+ VOID
+RejectSession(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG StatusCode,
+ IN ULONG SessionStatus,
+ IN BOOLEAN SendNegativeSessionResponse
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a negative session response (if the boolean is set)
+ and then disconnects the connection.
+ Cleanup connection could have been called to disconnect the call,
+ and it changes the state to disconnecting, so don't disconnected
+ again if that is happening.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ NTSTATUS status;
+ tCONNECTELE *pConnEle;
+ BOOLEAN DerefConnEle=FALSE;
+
+ //
+ // There is no listen event handler so return a status code to
+ // the caller indicating that this end is between "listens" and
+ // that they should try the setup again in a few milliseconds.
+ //
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt: No Listen or Connect Handlr so Disconnect! LowerConn=%X Session Status=%X\n",
+ pLowerConn,SessionStatus));
+
+ if (SendNegativeSessionResponse)
+ {
+ status = TcpSendSessionResponse(pLowerConn,
+ StatusCode,
+ SessionStatus);
+ }
+
+ // need to hold this lock if we are to un connect the lower and upper
+ // connnections
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ CTESpinLock(pLowerConn,OldIrq);
+
+ if ((pLowerConn->State < NBT_DISCONNECTING) &&
+ (pLowerConn->State > NBT_CONNECTING))
+ {
+ pLowerConn->State = NBT_DISCONNECTING;
+ SetStateProc( pLowerConn, RejectAnyData ) ;
+ CHECK_PTR(pLowerConn);
+
+ pConnEle = pLowerConn->pUpperConnection;
+ if (pConnEle)
+ {
+ CHECK_PTR(pConnEle);
+ CHECK_PTR(pLowerConn);
+ DerefConnEle = TRUE;
+ pLowerConn->pUpperConnection = NULL;
+ pConnEle->pLowerConnId = NULL;
+ }
+
+ CTESpinFree(pLowerConn,OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ SendTcpDisconnect((PVOID)pLowerConn);
+ }
+ else
+ {
+ CTESpinFree(pLowerConn,OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ }
+
+ if (DerefConnEle)
+ {
+ DereferenceIfNotInRcvHandler(pConnEle,pLowerConn);
+ }
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+FindSessionEndPoint(
+ IN PVOID pTsdu,
+ IN PVOID ConnectionContext,
+ IN ULONG BytesIndicated,
+ OUT tCLIENTELE **ppClientEle,
+ OUT PVOID *ppRemoteAddress,
+ OUT PULONG pRemoteAddressLength
+ )
+/*++
+
+Routine Description:
+
+ This routine attempts to find an end point on the node with the matching
+ net bios name. It is called at session setup time when a session request
+ PDU has arrived. The routine returns the Client Element ptr.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+
+ NTSTATUS status;
+ tCLIENTELE *pClientEle;
+ tLOWERCONNECTION *pLowerConn;
+ CHAR pName[NETBIOS_NAME_SIZE];
+ PUCHAR pScope;
+ tNAMEADDR *pNameAddr;
+ tADDRESSELE *pAddressEle;
+ PLIST_ENTRY pEntry;
+ PLIST_ENTRY pHead;
+ ULONG lNameSize;
+ tSESSIONREQ UNALIGNED *pSessionReq = (tSESSIONREQ UNALIGNED *)pTsdu;
+ USHORT sType;
+ CTELockHandle OldIrq2;
+ PUCHAR pSrcName;
+ BOOLEAN Found;
+
+ // get the ptr to the lower connection, and from that get the ptr to the
+ // upper connection block
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+
+ if (pSessionReq->Hdr.Type != NBT_SESSION_REQUEST)
+ {
+ return(SESSION_UNSPECIFIED_ERROR);
+ }
+
+ // get the called name out of the PDU
+ status = ConvertToAscii(
+ (PCHAR)&pSessionReq->CalledName.NameLength,
+ BytesIndicated - FIELD_OFFSET(tSESSIONREQ,CalledName.NameLength),
+ pName,
+ &pScope,
+ &lNameSize);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(SESSION_UNSPECIFIED_ERROR);
+ }
+
+
+ // now try to find the called name in this node's Local table
+ //
+
+ //
+ // in case a disconnect came in while the spin lock was released
+ //
+ if (pLowerConn->State != NBT_SESSION_INBOUND)
+ {
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ pNameAddr = FindName(NBT_LOCAL,pName,pScope,&sType);
+
+ if (!pNameAddr)
+ {
+ return(SESSION_CALLED_NAME_NOT_PRESENT);
+ }
+
+ // we got to here because the name has resolved to a name on this node,
+ // so accept the Session setup.
+ //
+ pAddressEle = (tADDRESSELE *)pNameAddr->pAddressEle;
+
+ // lock the address structure until we find a client on the list
+ //
+ CTESpinLock(pAddressEle,OldIrq2);
+
+ if (IsListEmpty(&pAddressEle->ClientHead))
+ {
+ CTESpinFree(pAddressEle,OldIrq2);
+ return(SESSION_NOT_LISTENING_ON_CALLED_NAME);
+ }
+
+ //
+ // get the first client on the list that is bound to the same
+ // devicecontext as the connection, with a listen posted, or a valid
+ // Connect event handler setup -
+ //
+ Found = FALSE;
+ pHead = &pAddressEle->ClientHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
+
+ if (pClientEle->pDeviceContext == pLowerConn->pDeviceContext)
+ {
+ //
+ // if there is a listen posted or a Connect Event Handler
+ // then allow the connect attempt to carry on, otherwise go to the
+ // next client in the list
+ //
+ if ((!IsListEmpty(&pClientEle->ListenHead)) ||
+ (pClientEle->ConEvContext))
+ {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ pEntry = pEntry->Flink;
+
+ }
+
+ if (!Found)
+ {
+ CTESpinFree(pAddressEle,OldIrq2);
+ return(SESSION_NOT_LISTENING_ON_CALLED_NAME);
+ }
+
+ // prevent the client from disappearing before we can indicate to him
+ //
+ CTEInterlockedIncrementLong(&pClientEle->RefCount);
+
+ pSrcName = (PUCHAR)((PUCHAR)&pSessionReq->CalledName.NameLength + lNameSize + 1);
+
+ status = MakeRemoteAddressStructure(
+ pSrcName,
+ 0,
+ BytesIndicated-lNameSize,
+ ppRemoteAddress,
+ pRemoteAddressLength,
+ 1);
+
+ if (!NT_SUCCESS(status))
+ {
+ CTESpinFree(pAddressEle,OldIrq2);
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+
+ NbtDereferenceClient(pClientEle);
+ CTESpinLockAtDpc(&NbtConfig.JointLock);
+
+ if (status == STATUS_INSUFFICIENT_RESOURCES)
+ {
+ return(SESSION_CALLED_NAME_PRESENT_NO_RESRC);
+ }
+ else
+ return(SESSION_UNSPECIFIED_ERROR);
+
+ }
+
+ CTESpinFree(pAddressEle,OldIrq2);
+
+ *ppClientEle = pClientEle;
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+MakeRemoteAddressStructure(
+ IN PCHAR pHalfAsciiName,
+ IN PVOID pSourceAddr,
+ IN ULONG lMaxNameSize,
+ OUT PVOID *ppRemoteAddress,
+ OUT PULONG pRemoteAddressLength,
+ IN ULONG NumAddr
+ )
+/*++
+
+Routine Description:
+
+ This routine makes up the remote addres structure with the netbios name
+ of the source in it, so that the info can be passed to the client...what
+ a bother to do this!
+
+Arguments:
+
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+ NTSTATUS status;
+ ULONG lNameSize;
+ CHAR pName[NETBIOS_NAME_SIZE];
+ PUCHAR pScope;
+ PTA_NETBIOS_ADDRESS pRemoteAddress;
+
+ // make up the remote address data structure to pass to the client
+ status = ConvertToAscii(
+ pHalfAsciiName,
+ lMaxNameSize,
+ pName,
+ &pScope,
+ &lNameSize);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+
+ pRemoteAddress = (PTA_NETBIOS_ADDRESS)NbtAllocMem(
+ NumAddr * sizeof(TA_NETBIOS_ADDRESS),NBT_TAG('2'));
+ if (!pRemoteAddress)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pRemoteAddress->TAAddressCount = NumAddr;
+ pRemoteAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
+ pRemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ pRemoteAddress->Address[0].Address[0].NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ CTEMemCopy(pRemoteAddress->Address[0].Address[0].NetbiosName,
+ pName,NETBIOS_NAME_SIZE);
+
+ *pRemoteAddressLength = FIELD_OFFSET(TA_NETBIOS_ADDRESS, Address[0].Address[0].NetbiosName[NETBIOS_NAME_SIZE]);
+
+ //
+ // Copy over the IP address also.
+ //
+ if (NumAddr == 2) {
+ TA_ADDRESS UNALIGNED *pTAAddr;
+ PTRANSPORT_ADDRESS pSourceAddress;
+ ULONG SubnetMask;
+
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSourceAddr;
+
+ pTAAddr = (TA_ADDRESS UNALIGNED *) (((PUCHAR)pRemoteAddress) + pRemoteAddress->Address[0].AddressLength + FIELD_OFFSET(TA_NETBIOS_ADDRESS, Address[0].Address));
+
+ pTAAddr->AddressLength = sizeof(TDI_ADDRESS_IP);
+ pTAAddr->AddressType = TDI_ADDRESS_TYPE_IP;
+ ((TDI_ADDRESS_IP UNALIGNED *)&pTAAddr->Address[0])->in_addr = ((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr;
+ *pRemoteAddressLength += (FIELD_OFFSET(TA_ADDRESS, Address) + pTAAddr->AddressLength);
+ }
+
+ *ppRemoteAddress = (PVOID)pRemoteAddress;
+// *pRemoteAddressLength = sizeof(TA_NETBIOS_ADDRESS);
+// *pRemoteAddressLength = FIELD_OFFSET(TA_NETBIOS_ADDRESS, Address[0].Address[0]);
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+ConnectHndlrNotOs (
+ IN PVOID pConnectionContext,
+ IN LONG RemoteAddressLength,
+ IN PVOID pRemoteAddress,
+ IN int UserDataLength,
+ IN VOID UNALIGNED *pUserData,
+ OUT CONNECTION_CONTEXT *ppConnectionId
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive connect indication handler.
+
+ It is called when a TCP connection is being setup for a NetBios session.
+ It simply allocates a connection and returns that information to the
+ transport so that the connect indication can be accepted.
+
+Arguments:
+
+ pClientEle - ptr to the connecition record for this session
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+ CTELockHandle OldIrq;
+ PLIST_ENTRY pList;
+ tLOWERCONNECTION *pLowerConn;
+ tDEVICECONTEXT *pDeviceContext;
+ PTRANSPORT_ADDRESS pSrcAddress;
+
+ pDeviceContext = (tDEVICECONTEXT *)pConnectionContext;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CTESpinLockAtDpc(pDeviceContext);
+
+ pSrcAddress = pRemoteAddress;
+
+ // get a free connection to the transport provider to accept this
+ // incoming connnection on.
+ //
+ if (IsListEmpty(&pDeviceContext->LowerConnFreeHead))
+ {
+ CTESpinFreeAtDpc(pDeviceContext);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // check that the source is an IP address
+ //
+ if (pSrcAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_IP)
+ {
+ CTESpinFreeAtDpc(pDeviceContext);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // take an idle connection and move it to the active connection list
+ //
+ pList = RemoveHeadList(&pDeviceContext->LowerConnFreeHead);
+
+ //
+ // If there are less than 2 connections remaining, we allocate another one. The check
+ // below is for 0 or 1 connections.
+ // In order to protect ourselves from SYN ATTACKS, allocate NbtConfig.SpecialConnIncrement more now until
+ // a certain (registry config) value is exhausted (NOTE this number is global and not
+ // per device).
+ //
+ if ((pDeviceContext->LowerConnFreeHead.Flink->Flink == &pDeviceContext->LowerConnFreeHead) &&
+ ((ULONG)InterlockedExchangeAdd(&NbtConfig.NumSpecialLowerConn, 0) <= NbtConfig.MaxBackLog)) {
+
+ if ((ULONG)InterlockedExchangeAdd(&NbtConfig.NumQueuedForAlloc, 0) == 0) {
+#ifndef VXD
+ KdPrint(("Queueing - SpecialLowerConn: %d, Actual: %d, NumQueuedForAlloc : %d\n",
+ NbtConfig.NumSpecialLowerConn,
+ NbtConfig.ActualNumSpecialLowerConn,
+ NbtConfig.NumQueuedForAlloc));
+#endif
+ CTEQueueForNonDispProcessing(
+ NULL,
+ pDeviceContext,
+ NULL,
+ DelayedAllocLowerConnSpecial,
+ pDeviceContext);
+
+ InterlockedExchangeAdd(&NbtConfig.NumSpecialLowerConn, NbtConfig.SpecialConnIncrement);
+ InterlockedIncrement(&NbtConfig.NumQueuedForAlloc);
+ }
+ }
+
+ InsertTailList(&pDeviceContext->LowerConnection,pList);
+
+ pLowerConn = CONTAINING_RECORD(pList,tLOWERCONNECTION,Linkage);
+
+ pLowerConn->State = NBT_SESSION_INBOUND;
+ pLowerConn->StateRcv = NORMAL;
+
+ SetStateProc( pLowerConn, Inbound ) ;
+
+ // this end is NOT the originator
+ pLowerConn->bOriginator = FALSE;
+
+ // increase the reference count because we are now connected. Decrement
+ // it when we disconnect.
+ //
+ ASSERT(pLowerConn->RefCount == 1);
+ CTEInterlockedIncrementLong(&pLowerConn->RefCount);
+ // save the source clients IP address into the connection Structure
+ // *TODO check if we need to do this or not
+ //
+ pLowerConn->SrcIpAddr =
+ ((PTDI_ADDRESS_IP)&pSrcAddress->Address[0].Address[0])->in_addr;
+
+ CTESpinFreeAtDpc(pDeviceContext);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ *ppConnectionId = (PVOID)pLowerConn;
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+DisconnectHndlrNotOs (
+ PVOID EventContext,
+ PVOID ConnectionContext,
+ ULONG DisconnectDataLength,
+ PVOID pDisconnectData,
+ ULONG DisconnectInformationLength,
+ PVOID pDisconnectInformation,
+ ULONG DisconnectIndicators
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive disconnect indication handler. It is called
+ by the transport when a connection disconnects. It checks the state of
+ the lower connection and basically returns a disconnect request to the
+ transport, except in the case where there is an active session. In this
+ case it calls the the clients disconnect indication handler. The client
+ then turns around and calls NbtDisconnect(in some cases), which passes a disconnect
+ back to the transport. The transport won't disconnect until it receives
+ a disconnect request from its client (NBT). If the flag TDI_DISCONNECT_ABORT
+ is set then there is no need to pass back a disconnect to the transport.
+
+ Since the client doesn't always issue a disconnect (i.e. the server),
+ this routine always turns around and issues a disconnect to the transport.
+ In the disconnect done handling, the lower connection is put back on the
+ free list if it is an inbound connection. For out bound connection the
+ lower and upper connections are left connected, since these will always
+ receive a cleanup and close connection from the client (i.e. until the
+ client does a close the lower connection will not be freed for outbound
+ connections).
+
+Arguments:
+
+ pClientEle - ptr to the connecition record for this session
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq2;
+ CTELockHandle OldIrq3;
+ CTELockHandle OldIrq4;
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnectEle;
+ tCLIENTELE *pClientEle;
+ USHORT state;
+ BOOLEAN CleanupLower=FALSE;
+ USHORT stateLower;
+ PIRP pIrp= NULL;
+ PIRP pIrpClose= NULL;
+ PIRP pIrpRcv= NULL;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tTIMERQENTRY *pTimerEntry;
+ BOOLEAN InsertOnList=FALSE;
+ BOOLEAN DisconnectIt=FALSE;
+ ULONG StateRcv;
+ COMPLETIONCLIENT pCompletion;
+
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+ pConnectEle = pLowerConn->pUpperConnection;
+ PUSH_LOCATION(0x63);
+
+ CHECK_PTR(pLowerConn);
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Disc Indication, LowerConn state = %X %X\n",
+ pLowerConn->State,pLowerConn));
+
+ // get the current state with the spin lock held to avoid a race condition
+ // with the client disconnecting
+ //
+ if (pConnectEle)
+ {
+ if ( (pConnectEle->Verify != NBT_VERIFY_CONNECTION) &&
+ (pConnectEle->Verify != NBT_VERIFY_CONNECTION_DOWN))
+ {
+ // ASSERT( FALSE ) ; Put back in after problem is fixed
+#ifdef VXD
+ CTEPrint("\bDisconnectHndlrNotOs: Disconnect indication after already disconnect!!\b\r\n") ;
+#endif
+ return STATUS_UNSUCCESSFUL ;
+ }
+ CHECK_PTR(pConnectEle);
+
+ // need to hold the joint lock if unconnecting the lower and upper
+ // connections.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq4);
+ CTESpinLock(pConnectEle,OldIrq2);
+
+ //
+ // We got a case where the ClientEle ptr was null. This shd not happen since the
+ // connection shd be associated at this time.
+ // Assert for that case to track this better.
+ //
+ ASSERT(pConnectEle->pClientEle);
+ CTESpinLock(pConnectEle->pClientEle,OldIrq3);
+ CTESpinLock(pLowerConn,OldIrq);
+ state = pConnectEle->state;
+ stateLower = pLowerConn->State;
+
+#ifdef VXD
+ DbgPrint("DisconnectHndlrNotOs: pConnectEle->state = 0x") ;
+ DbgPrintNum( (ULONG) state ) ;
+ DbgPrint("pLowerConn->state = 0x") ; DbgPrintNum( (ULONG) stateLower ) ;
+ DbgPrint("\r\n") ;
+#endif
+
+ if ((state > NBT_ASSOCIATED) && (state < NBT_DISCONNECTING))
+ {
+
+ PUSH_LOCATION(0x63);
+ CHECK_PTR(pConnectEle);
+
+ CHECK_PTR(pConnectEle);
+ //
+ // this irp gets returned to the client below in the case statement
+ // Except in the connecting state where the transport still has
+ // the irp. In that case we let SessionStartupContinue complete
+ // the irp.
+ //
+ if ((pConnectEle->pIrp) && (state > NBT_CONNECTING))
+ {
+ pIrp = pConnectEle->pIrp;
+ pConnectEle->pIrp = NULL;
+ }
+
+ //
+ // if there is a receive irp, get it out of pConnEle since pConnEle
+ // will be requeued and could get used again before we try to
+ // complete this irp down below. Null the cancel routine if not
+ // cancelled and just complete it below.
+ //
+ if (((state == NBT_SESSION_UP) || (state == NBT_SESSION_WAITACCEPT))
+ && (pConnectEle->pIrpRcv))
+ {
+ CTELockHandle OldIrql;
+
+ pIrpRcv = pConnectEle->pIrpRcv;
+
+#ifndef VXD
+ IoAcquireCancelSpinLock(&OldIrql);
+ //
+ // if its already cancelled then don't complete it again
+ // down below
+ //
+ if (pIrpRcv->Cancel)
+ {
+ pIrpRcv = NULL;
+ }
+ else
+ {
+ IoSetCancelRoutine(pIrpRcv,NULL);
+ }
+ IoReleaseCancelSpinLock(OldIrql);
+#endif
+ pConnectEle->pIrpRcv = NULL;
+ }
+
+ // This irp is used for DisconnectWait
+ //
+ if (pIrpClose = pConnectEle->pIrpClose)
+ {
+ pConnectEle->pIrpClose = NULL;
+ }
+
+ pConnectEle->state = NBT_ASSOCIATED;
+ pConnectEle->pLowerConnId = NULL;
+ //
+ // save whether it is a disconnect abort or disconnect release
+ // in case the client does a disconnect wait and wants the
+ // real disconnect status i.e. they do not have a disconnect
+ // indication handler
+ //
+ pConnectEle->DiscFlag = (UCHAR)DisconnectIndicators;
+
+#ifdef VXD
+ if ( pLowerConn->StateRcv == PARTIAL_RCV &&
+ (pLowerConn->fOnPartialRcvList == TRUE) )
+ {
+ RemoveEntryList( &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+ }
+#endif
+
+ pLowerConn->State = NBT_DISCONNECTING;
+ pLowerConn->pUpperConnection = NULL;
+
+ //
+ // pConnectEle is dereferenced below, now that the lower conn
+ // no longer points to it.
+ //
+ InsertOnList = TRUE;
+
+ DisconnectIt = TRUE;
+
+ //
+ // put pConnEle back on the list of idle connection for this
+ // client
+ //
+ RemoveEntryList(&pConnectEle->Linkage);
+ InsertTailList(&pConnectEle->pClientEle->ConnectHead,&pConnectEle->Linkage);
+
+ if (DisconnectIndicators == TDI_DISCONNECT_RELEASE)
+ {
+ // setting the state to disconnected will allow the DisconnectDone
+ // routine in updsend.c to cleanupafterdisconnect, when the disconnect
+ // completes (since we have been indicated)
+ //
+ pLowerConn->State = NBT_DISCONNECTED;
+ }
+ else
+ {
+ // there is no disconnect completion to wait for ...since it
+ // was an abortive disconnect indication
+ // Change the state of the lower conn incase the client has
+ // done a disconnect at the same time - we don't want DisconnectDone
+ // to also Queue up CleanupAfterDisconnect
+ //
+ pLowerConn->State = NBT_IDLE;
+ }
+ }
+ //
+ // the lower connection just went from disconnecting to disconnected
+ // so change the state - this signals the DisconnectDone routine to
+ // cleanup the connection when the disconnect request completes.
+ //
+ if (stateLower == NBT_DISCONNECTING)
+ {
+ pLowerConn->State = NBT_DISCONNECTED;
+ }
+ else
+ if (stateLower == NBT_DISCONNECTED)
+ {
+ //
+ // we get to here if the disconnect request Irp completes before the
+ // disconnect indication comes back. The disconnect completes
+ // and checks the state, changing it to Disconnected if it
+ // isn't already - see disconnectDone in udpsend.c. Since
+ // the disconnect indication and the disconnect completion
+ // have occurred, cleanup the connection.
+ //
+ CleanupLower = TRUE;
+
+ // this is just a precaution that may not be needed, so we
+ // don't queue the cleanup twice...i.e. now that the lower state
+ // is disconnected, we change it's state to idle incase the
+ // transport hits us again with another disconnect indication.
+ // QueueCleanup is called below based on the value in statelower
+ pLowerConn->State = NBT_IDLE;
+ }
+ //
+ // During the time window that a connection is being setup and TCP
+ // completes the connect irp, we could get a disconnect indication.
+ // the RefCount must be incremented here so that CleanupAfterDisconnect
+ // does not delete the connection (i.e. it expects refcount >= 2).
+ //
+ if (stateLower <= NBT_CONNECTING)
+ {
+ pLowerConn->RefCount++;
+ }
+
+ CTESpinFree(pLowerConn,OldIrq);
+ CTESpinFree(pConnectEle->pClientEle,OldIrq3);
+ CTESpinFree(pConnectEle,OldIrq2);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq4);
+
+
+ }
+ else
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq2);
+ CTESpinLock(pLowerConn,OldIrq);
+ stateLower = pLowerConn->State;
+ state = NBT_IDLE;
+
+ if ((stateLower > NBT_IDLE) && (stateLower < NBT_DISCONNECTING))
+ {
+ // flag so we send back a disconnect to the transport
+ DisconnectIt = TRUE;
+ //
+ // set state so that DisconnectDone will cleanup the connection.
+ //
+ pLowerConn->State = NBT_DISCONNECTED;
+ //
+ // for an abortive disconnect we will do a cleanup below, so
+ // set the state to idle here
+ //
+ if (DisconnectIndicators != TDI_DISCONNECT_RELEASE)
+ {
+ pLowerConn->State = NBT_IDLE;
+ }
+
+ } else
+ if ( stateLower == NBT_DISCONNECTING )
+ {
+ // a Disconnect has already been initiated by this side so when
+ // DisconnectDone runs it will cleanup
+ //
+ pLowerConn->State = NBT_DISCONNECTED ;
+ }
+ else
+ if ( stateLower == NBT_DISCONNECTED )
+ {
+ CleanupLower = TRUE;
+ pLowerConn->State = NBT_IDLE;
+ }
+
+ //
+ // During the time window that a connection is being setup and TCP
+ // completes the connect irp, we could get a disconnect indication.
+ // the RefCount must be incremented here so that CleanupAfterDisconnect
+ // does not delete the connection (i.e. it expects refcount >= 2).
+ //
+ if ((stateLower <= NBT_CONNECTING) &&
+ (stateLower > NBT_IDLE))
+ {
+ pLowerConn->RefCount++;
+ }
+ CTESpinFree(pLowerConn,OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+
+ }
+
+ StateRcv = pLowerConn->StateRcv;
+ SetStateProc( pLowerConn, RejectAnyData ) ;
+
+ if (DisconnectIt)
+ {
+ if (DisconnectIndicators == TDI_DISCONNECT_RELEASE)
+ {
+ // this disconnects the connection and puts the lowerconn back on
+ // its free queue. Note that OutOfRsrcKill calls this routine too
+ // with the DisconnectIndicators set to Abort, and the code correctly
+ // does not attempt to disconnect the connection since the OutOfRsrc
+ // routine had already disconnected it.
+ //
+ PUSH_LOCATION(0x6d);
+ status = SendTcpDisconnect((PVOID)pLowerConn);
+
+ }
+ else
+ {
+ // this is an abortive disconnect from the transport, so there is
+ // no need to send a disconnect request back to the transport.
+ // So we set a flag that tells us later in the routine to close
+ // the lower connection.
+ //
+ PUSH_LOCATION(0x69);
+ CleanupLower = TRUE;
+ }
+ }
+
+ //
+ // for an orderly release, turn around and send a release to the transport
+ // if there is no client attached to the lower connection. If there is a
+ // client then we must pass the disconnect indication to the client and
+ // wait for the client to do the disconnect.
+ //
+ //
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:ConnEle state = %X, %X\n",state,(ULONG)pConnectEle));
+
+ switch (state)
+ {
+
+ case NBT_SESSION_INBOUND:
+ case NBT_CONNECTING:
+
+ // if an originator, then the upper and lower connections are
+ // already associated, and there is a client irp to return.
+ // (NBT_SESSION_CONNECTING only)
+ //
+ if (pIrp)
+ {
+ if (pLowerConn->bOriginator)
+ {
+ CTEIoComplete(pIrp,
+ STATUS_BAD_NETWORK_PATH,
+ 0);
+ }
+ else
+ {
+ // this could be an inbound call that could not send the
+ // session response correctly.
+ //
+ CTEIoComplete(pIrp,
+ STATUS_UNSUCCESSFUL,
+ 0);
+ }
+
+ }
+
+ break;
+
+ case NBT_SESSION_OUTBOUND:
+ //
+ //
+ // Stop the timer started in SessionStartupCompletion to time the
+ // Session Setup Response message
+ //
+ // NbtConnect stores the tracker in the IrpRcv ptr so that this
+ // routine can access it
+ //
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ CTESpinLock(pConnectEle,OldIrq2);
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pConnectEle->pIrpRcv;
+
+ //
+ // check if anyone else has freed the tracker yet.
+ //
+ if (pTracker)
+ {
+ pConnectEle->pIrpRcv = NULL;
+ pTimerEntry = pTracker->Connect.pTimer;
+ CHECK_PTR(pTracker);
+ pTracker->Connect.pTimer = NULL;
+
+ CTESpinFree(pConnectEle,OldIrq2);
+
+ //
+ // if the timer has expired it will not cleanup because the state
+ // will not be SESSION_OUTBOUND, since we changed it above to
+ // disconnected. So we always have to complete the irp and
+ // call cleanupafterdisconnect below.
+ //
+ if (pTimerEntry)
+ {
+ StopTimer(pTimerEntry,&pCompletion,NULL);
+ }
+
+ //
+ // Check if the SessionStartupCompletion has run; if so, RefConn will be 0.
+ // Else, decrement so that the tracker goes away when the session send completes.
+ //
+ // [BUGBUGWISHLIST]: Do we need the Jointlock to protect this? use InterlockedIncrement
+ // instead....
+ //
+ if (pTracker->RefConn == 0)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
+ }
+ else
+ {
+ pTracker->RefConn--;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ }
+ else
+ {
+ CTESpinFree(pConnectEle,OldIrq2);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+
+ if (pIrp)
+ {
+ CTEIoComplete(pIrp,STATUS_REMOTE_NOT_LISTENING,0);
+ }
+
+ break;
+
+ case NBT_SESSION_WAITACCEPT:
+ case NBT_SESSION_UP:
+
+ if (pIrp)
+ {
+ CTEIoComplete(pIrp,STATUS_CANCELLED,0);
+ }
+ //
+ // check for any RcvIrp that may be still around. If the
+ // transport has the Irp now then pIrpRcv = NULL. There should
+ // be no race condition between completing it and CompletionRcv
+ // setting pIrpRcv again as long as we cannot be indicated
+ // for a disconnect during completion of a Receive. In any
+ // case the access is coordinated using the Io spin lock io
+ // IoCancelIrp - that routine will only complete the irp once,
+ // then it nulls the completion routine.
+ //
+ if ((StateRcv == FILL_IRP) && pIrpRcv)
+ {
+
+ PUSH_LOCATION(0x6f);
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Cancelling RcvIrp on Disconnect Indication!!!\n"));
+
+ CTEIoComplete(pIrpRcv,STATUS_CANCELLED,0);
+ }
+
+ //
+ // this is a disconnect for an active session, so just inform the client
+ // and then it issues a Nbtdisconnect. We have already disconnected the
+ // lowerconnection with the transport, so all that remains is
+ // to cleanup for outgoing calls.
+ //
+
+ pClientEle = pConnectEle->pClientEle;
+
+ // now call the client's disconnect handler...NBT always does
+ // a abortive disconnect - i.e. the connection is closed when
+ // the disconnect indication occurs and does not REQUIRE a
+ // disconnect from the client to finish the job.( a disconnect
+ // from the client will not hurt though.
+ //
+ PUSH_LOCATION(0x64);
+ if ((pClientEle && pClientEle->evDisconnect ) &&
+ (!pIrpClose))
+
+ {
+ status = (*pClientEle->evDisconnect)(pClientEle->DiscEvContext,
+ pConnectEle->ConnectContext,
+ DisconnectDataLength,
+ pDisconnectData,
+ DisconnectInformationLength,
+ pDisconnectInformation,
+ TDI_DISCONNECT_ABORT);
+ }
+ else
+ if (pIrpClose)
+ {
+ //
+ // the Client has issued a disconnect Wait irp, so complete
+ // it now, indicating to them that a disconnect has occurred.
+ //
+ if (DisconnectIndicators == TDI_DISCONNECT_RELEASE)
+ {
+ status = STATUS_GRACEFUL_DISCONNECT;
+ }
+ else
+ status = STATUS_CONNECTION_RESET;
+
+ CTEIoComplete(pIrpClose,status,0);
+
+ }
+
+ //
+ // return any rcv buffers that have been posted
+ //
+ CTESpinLock(pConnectEle,OldIrq);
+
+ FreeRcvBuffers(pConnectEle,&OldIrq);
+
+ CTESpinFree(pConnectEle,OldIrq);
+
+ break;
+
+ case NBT_DISCONNECTING:
+ // the retry session setup code expects the state to change
+ // to disconnected when the disconnect indication comes
+ // from the wire
+ pConnectEle->state = NBT_DISCONNECTED;
+
+ case NBT_DISCONNECTED:
+ case NBT_ASSOCIATED:
+ case NBT_IDLE:
+
+ //
+ // catch all other cases here to be sure the connect irp gets
+ // returned.
+ //
+ if (pIrp)
+ {
+ CTEIoComplete(pIrp,STATUS_CANCELLED,0);
+ }
+ break;
+
+ default:
+ ASSERTMSG("Nbt:Disconnect indication in unexpected state\n",0);
+
+ }
+
+ if (InsertOnList)
+ {
+ // undo the reference done when the NbtConnect Ran - this may cause
+ // pConnEle to be deleted if the Client had issued an NtClose before
+ // this routine ran. We only do this dereference if InsertOnList is
+ // TRUE, meaning that we just "unhooked" the lower from the Upper.
+ PUSH_LOCATION(0x65);
+ DereferenceIfNotInRcvHandler(pConnectEle,pLowerConn);
+ }
+
+
+ // this either puts the lower connection back on its free
+ // queue if inbound, or closes the connection with the transport
+ // if out bound. (it can't be done at dispatch level).
+ //
+ if (CleanupLower)
+ {
+ PUSH_LOCATION(0x6B);
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Calling Worker thread to Cleanup Disconnect %X\n",pLowerConn));
+
+ CTESpinLock(pLowerConn,OldIrq);
+
+ if ( pLowerConn->pIrp )
+ {
+ PCTE_IRP pIrp;
+
+ pIrp = pLowerConn->pIrp;
+ CHECK_PTR(pLowerConn);
+ pLowerConn->pIrp = NULL ;
+
+ CTESpinFree(pLowerConn,OldIrq);
+ // this is the irp to complete when the disconnect completes - essentially
+ // the irp requesting the disconnect.
+ CTEIoComplete( pIrp, STATUS_SUCCESS, 0 ) ;
+ }
+ else
+ CTESpinFree(pLowerConn,OldIrq);
+
+#if !defined(VXD) && DBG
+ if ((pLowerConn->Verify != NBT_VERIFY_LOWERCONN ) ||
+ (pLowerConn->RefCount == 1))
+ {
+ DbgBreakPoint();
+ }
+#endif
+
+ status = CTEQueueForNonDispProcessing(
+ NULL,
+ pLowerConn,
+ NULL,
+ CleanupAfterDisconnect,
+ pLowerConn->pDeviceContext);
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+CleanupAfterDisconnect(
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles freeing lowerconnection data structures back to the
+ transport, by calling NTclose (outbound only) or by putting the connection
+ back on the connection free queue (inbound only). For the NT case this
+ routine runs within the context of an excutive worker thread.
+
+Arguments:
+
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+ CTELockHandle OldIrq;
+ NTSTATUS status;
+ tLOWERCONNECTION *pLowerConn;
+ tDEVICECONTEXT *pDeviceContext;
+ PIRP pIrp=NULL;
+
+ PUSH_LOCATION(0x67);
+ pLowerConn = (tLOWERCONNECTION*)((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:CleanupDisconnect Orig= %X, pLowerConn=%X\n",
+ pLowerConn->bOriginator,pLowerConn));
+
+ //
+ // DEBUG to catch upper connections being put on lower conn QUEUE
+ //
+#if !defined(VXD) && DBG
+ if ((pLowerConn->Verify != NBT_VERIFY_LOWERCONN ) ||
+ (pLowerConn->RefCount == 1))
+ {
+ DbgBreakPoint();
+ }
+#endif
+
+ ASSERT(pLowerConn->pUpperConnection == NULL);
+ //
+ // Inbound lower connections just get put back on the queue, whereas
+ // outbound connections get closed.
+ //
+ // Connections allocated due to SynAttack backlog measures are not re-allocated
+ //
+ if (!(pLowerConn->bOriginator || pLowerConn->SpecialAlloc))
+ {
+ // ******** INCOMING *************
+ pDeviceContext = pLowerConn->pDeviceContext;
+ //
+ // if Dhcp says the lease on the Ip address has gone , then this
+ // boolean is set in NbtNewDhcpAddress, to tell this code to close
+ // the connection.
+ //
+ if (pLowerConn->DestroyConnection)
+ {
+ status = NbtDeleteLowerConn(pLowerConn);
+ }
+ else
+ {
+
+ //
+ // Always close the connection and then Create another since there
+ // could be a Rcv Irp in TCP still that will be returned at some
+ // later time, perhaps after this connection gets reused again.
+ // In that case the Rcv Irp could be lost.
+
+ PUSH_LOCATION(0x68);
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:CleanupDisconnect Lower Conn State = %X %X\n",
+ pLowerConn->State,pLowerConn));
+
+ ASSERT(pLowerConn->RefCount >= 2);
+ NbtDereferenceLowerConnection(pLowerConn);
+
+ status = NbtDeleteLowerConn(pLowerConn);
+ CHECK_PTR(pLowerConn);
+
+ AllocLowerConn(pDeviceContext, FALSE);
+
+ }
+ }
+ else
+ {
+ // ******** OUTGOING *************
+
+ PUSH_LOCATION(0x6B);
+ // this deref removes the reference added when the connection
+ // connnected. When NbtDeleteLowerConn is called it dereferences
+ // one more time which delete the memory.
+ //
+ NbtDereferenceLowerConnection(pLowerConn);
+ CHECK_PTR(pLowerConn);
+
+ // this does a close on the lower connection, so it can go ahead
+ // possibly before the disconnect has completed since the transport
+ // will not complete the close until is completes the disconnect.
+ //
+ status = NbtDeleteLowerConn(pLowerConn);
+
+ //
+ // If this was a special connection block, decrement the count of such connections
+ //
+ if (pLowerConn->SpecialAlloc) {
+ InterlockedDecrement(&NbtConfig.NumSpecialLowerConn);
+#if DBG
+ InterlockedDecrement(&NbtConfig.ActualNumSpecialLowerConn);
+#endif
+#ifndef VXD
+ KdPrint(("Nbt:CleanupDisconnect Special Lower Conn;NumSpecialLowerConn= %d, Actual: %d\n",
+ NbtConfig.NumSpecialLowerConn, NbtConfig.ActualNumSpecialLowerConn));
+#endif
+ }
+ }
+ CTEMemFree(pContext);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+AllocLowerConn(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN BOOLEAN fSpecial
+ )
+/*++
+
+Routine Description:
+
+ Allocate a lowerconn block that will go on the lowerconnfreehead.
+
+Arguments:
+
+ pDeviceContext - the device context
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status;
+ tLOWERCONNECTION *pLowerConn;
+
+
+ pLowerConn = (tLOWERCONNECTION *)NbtAllocMem(sizeof(tLOWERCONNECTION),NBT_TAG('3'));
+
+ if (pLowerConn)
+ {
+ status = NbtOpenAndAssocConnection(pLowerConn,pDeviceContext);
+ if (!NT_SUCCESS(status))
+ {
+ CTEMemFree(pLowerConn);
+ pLowerConn = NULL;
+ } else if (fSpecial) {
+ //
+ // Special lowerconn for Syn attacks
+ //
+ pLowerConn->SpecialAlloc = TRUE;
+ }
+ }
+
+ //
+ // if malloc failed or if NbtOpenAndAsso... failed, schedule an event
+ //
+ if (!pLowerConn)
+ {
+ CTEQueueForNonDispProcessing(
+ NULL,
+ pDeviceContext,
+ NULL,
+ DelayedAllocLowerConn,
+ pDeviceContext);
+ }
+
+}
+//----------------------------------------------------------------------------
+ VOID
+DelayedAllocLowerConn(
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ If lowerconn couldn't be alloced in AllocLowerConn, an event is scheduled
+ so that we can retry later. Well, this is "later"!
+
+Arguments:
+
+
+
+Return Value:
+
+
+--*/
+{
+ tDEVICECONTEXT *pDeviceContext;
+
+
+ pDeviceContext = (tDEVICECONTEXT *)((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
+
+ ASSERT( pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
+
+ AllocLowerConn(pDeviceContext, FALSE);
+
+ CTEMemFree(pContext);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+DelayedAllocLowerConnSpecial(
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ If lowerconn couldn't be alloced in AllocLowerConn, an event is scheduled
+ so that we can retry later. Well, this is "later"!
+
+ This is for SYN-ATTACK, so we shd create more than one to beat the incoming
+ requests. Create three at a time - this shd be controllable thru' registry.
+
+Arguments:
+
+
+
+Return Value:
+
+
+--*/
+{
+ tDEVICECONTEXT *pDeviceContext;
+ ULONG i;
+
+ KdPrint(("Allocing spl. %d lowerconn...\n", NbtConfig.SpecialConnIncrement));
+
+ pDeviceContext = (tDEVICECONTEXT *)((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
+
+ ASSERT( pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
+
+ //
+ // Alloc SpecialConnIncrement number of more connections.
+ //
+ for (i=0; i<NbtConfig.SpecialConnIncrement; i++) {
+#if DBG
+ InterlockedIncrement(&NbtConfig.ActualNumSpecialLowerConn);
+#endif
+ AllocLowerConn(pDeviceContext, TRUE);
+ }
+
+ InterlockedDecrement(&NbtConfig.NumQueuedForAlloc);
+
+ CTEMemFree(pContext);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+AddToRemoteHashTbl (
+ IN tDGRAMHDR UNALIGNED *pDgram,
+ IN ULONG BytesIndicated,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine adds the source address of an inbound datagram to the remote
+ hash table so that it can be used for subsequent return sends to that node.
+
+ This routine does not need to be called if the datagram message type is
+ Broadcast datagram, since these are sends to the broadcast name '*' and
+ there is no send caching this source name
+
+Arguments:
+
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+ tNAMEADDR *pNameAddr;
+ CTELockHandle OldIrq;
+ UCHAR pName[NETBIOS_NAME_SIZE];
+ NTSTATUS status;
+ LONG Length;
+ ULONG SrcIpAddr;
+ enum eNbtAddrType AddrType;
+ PUCHAR pScope;
+
+ // find the src name in the header.
+ status = ConvertToAscii(
+ (PCHAR)&pDgram->SrcName.NameLength,
+ (ULONG)((PCHAR)BytesIndicated - FIELD_OFFSET(tDGRAMHDR,SrcName.NameLength)),
+ pName,
+ &pScope,
+ &Length);
+
+ if (!NT_SUCCESS(status))
+ {
+ return;
+ }
+
+ SrcIpAddr = ntohl(pDgram->SrcIpAddr);
+ //
+ // source ip addr should never be 0. This is a workaround for UB's NBDD
+ // which forwards the datagram, but client puts 0 in SourceIpAddr field
+ // of the datagram, we cache 0 and then end up doing a broadcast when we
+ // really meant to do a directed datagram to the sender.
+ //
+ if (!SrcIpAddr)
+ return;
+
+ // always a unique address since you can't send from a group name
+ //
+ AddrType = NBT_UNIQUE;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ //
+ // Add the name to the remote cache.
+ //
+ status = AddNotFoundToHashTable(NbtConfig.pRemoteHashTbl,
+ pName,
+ pScope,
+ SrcIpAddr,
+ AddrType,
+ &pNameAddr);
+
+ if (NT_SUCCESS(status))
+ {
+ //
+ // we only want the name to be in the remote cache for the shortest
+ // timeout allowed by the remote cache timer, so set the timeout
+ // count to 1 which is 1-2 minutes.
+ //
+
+ // the name is already in the cache when Pending is returned,
+ // so just update the ip address in case it is different.
+ //
+ if (status == STATUS_PENDING)
+ {
+ //
+ // If the name is resolved then it is ok to overwrite the
+ // ip address with the incoming one. But if it is resolving,
+ // then just let it continue resolving.
+ //
+ if ( (pNameAddr->NameTypeState & STATE_RESOLVED) &&
+ !(pNameAddr->NameTypeState & NAMETYPE_INET_GROUP))
+ {
+ pNameAddr->IpAddress = SrcIpAddr;
+ pNameAddr->TimeOutCount = 1;
+ // only set the adapter mask for this adapter since we are
+ // only sure that this adapter can reach the dest.
+ pNameAddr->AdapterMask = pDeviceContext->AdapterNumber;
+ }
+ }
+ else
+ {
+ pNameAddr->TimeOutCount = 1;
+ //
+ // change the state to resolved
+ //
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= STATE_RESOLVED;
+ pNameAddr->AdapterMask |= pDeviceContext->AdapterNumber;
+ }
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+DgramHndlrNotOs (
+ IN PVOID ReceiveEventContext,
+ IN ULONG SourceAddrLength,
+ IN PVOID pSourceAddr,
+ IN ULONG OptionsLength,
+ IN PVOID pOptions,
+ IN ULONG ReceiveDatagramFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG pBytesTaken,
+ IN PVOID pTsdu,
+ OUT PVOID *ppRcvBuffer,
+ IN tCLIENTLIST **ppClientList
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive datagram event indication handler.
+
+ It is called when an a datgram arrives from the network. The code
+ checks the type of datagram and then tries to route the datagram to
+ the correct destination on the node.
+
+ This procedure is called with the spin lock held on pDeviceContext.
+
+Arguments:
+
+ ppRcvbuffer will contain the IRP/NCB if only one client is listening,
+ NULL if multiple clients are listening
+ ppClientList will contain the list clients that need to be completed,
+ NULL if only one client is listening
+
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+ NTSTATUS status;
+ NTSTATUS LocStatus;
+ tCLIENTELE *pClientEle;
+ tNAMEADDR *pNameAddr;
+ tADDRESSELE *pAddress;
+ USHORT RetNameType;
+ CTELockHandle OldIrq;
+ CHAR pName[NETBIOS_NAME_SIZE];
+ PUCHAR pScope;
+ ULONG uLength;
+ int iLength;
+ ULONG RemoteAddressLength;
+ PVOID pRemoteAddress;
+ tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)ReceiveEventContext;
+ tDGRAMHDR UNALIGNED *pDgram = (tDGRAMHDR UNALIGNED *)pTsdu;
+ ULONG lClientBytesTaken;
+ ULONG lDgramHdrSize;
+ PIRP pIrp;
+ BOOLEAN MoreClients;
+ BOOLEAN UsingClientBuffer;
+ CTEULONGLONG AdapterNumber;
+ ULONG BytesIndicatedOrig;
+ ULONG BytesAvailableOrig;
+
+ //
+ // Check a few things first
+ //
+ if (BytesIndicated < 11)
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ status = STATUS_DATA_NOT_ACCEPTED;
+
+ // Check Normal DataGrams
+ //
+ if ((pDgram->MsgType >= DIRECT_UNIQUE) &&
+ (pDgram->MsgType <= BROADCAST_DGRAM))
+ {
+ ULONG Offset;
+
+ // there must be at least the header plus two half ascii names etc.
+ // which all adds up to 82 bytes with no user data
+ //
+ if (BytesIndicated < 82 )
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // find the end of the SourceName .. it ends in a 0 byte so use
+ // strlen
+ iLength = strlen((PCHAR)pDgram->SrcName.NetBiosName);
+
+ if (iLength <= 0)
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ //
+ // find the destination name in the local name service tables
+ //
+ Offset = iLength + FIELD_OFFSET(tDGRAMHDR,SrcName.NetBiosName[0]);
+ LocStatus = ConvertToAscii(
+ (PCHAR)&pDgram->SrcName.NetBiosName[iLength+1],
+ BytesIndicated-Offset,
+ pName,
+ &pScope,
+ &uLength);
+
+ if (!NT_SUCCESS(LocStatus))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ //
+ // check length again, including scopes of names too. The Src
+ // scope length is returned in uLength, which also includes the
+ // half ascii length and the length byte length
+ //
+ if (BytesIndicated < (82 + NbtConfig.ScopeLength -1 +
+ (uLength -2*NETBIOS_NAME_SIZE -1 )))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // Check for the full name first instead of considering any name with a '*' as
+ // the first char as a broadcast name (e.g. *SMBSERVER and *SMBDATAGRAM are not
+ // b'cast names).
+ //
+ pNameAddr = (tNAMEADDR *)FindName(
+ NBT_LOCAL,
+ pName,
+ pScope,
+ &RetNameType);
+
+ //
+ // If we failed above, it might be because the name could start with '*' and is a
+ // bcast name.
+ //
+ if (!pNameAddr) {
+ //
+ // be sure the broadcast name has 15 zeroes after it
+ //
+ if (pName[0] == '*')
+ {
+ CTEZeroMemory(&pName[1],NETBIOS_NAME_SIZE-1);
+ pNameAddr = (tNAMEADDR *)FindName(
+ NBT_LOCAL,
+ pName,
+ pScope,
+ &RetNameType);
+ }
+ }
+
+ // Change the pTsdu ptr to pt to the users data
+ // -2 to account for the tNETBIOSNAME and +3 to add the length
+ // bytes for both names, plus the null on the end of the first
+ // name
+
+ lDgramHdrSize = sizeof(tDGRAMHDR) - 2 + 3+ iLength + uLength;
+ pTsdu = (PVOID)((PUCHAR)pTsdu + lDgramHdrSize);
+ BytesAvailableOrig = BytesAvailable;
+ BytesAvailable -= lDgramHdrSize;
+ BytesIndicatedOrig = BytesIndicated;
+ BytesIndicated -= lDgramHdrSize;
+
+ //
+ // If the name is in the local table and has an address element
+ // associated with it AND the name is registered against
+ // this adapter, then execute the code in the 'if' block
+ //
+ AdapterNumber = pDeviceContext->AdapterNumber;
+ if ((pNameAddr) && (pNameAddr->pAddressEle) &&
+ ( AdapterNumber & pNameAddr->AdapterMask))
+ {
+ pAddress = pNameAddr->pAddressEle;
+
+ //
+ // Increment the reference count to prevent the
+ // pAddress from disappearing in the window between freeing
+ // the JOINT_LOCK and taking the ADDRESS_LOCK. We also need to
+ // keep the refcount if we are doing a multi client recv, since
+ // Clientlist access pAddressEle when distributing the rcv'd dgram
+ // in CompletionRcvDgram.
+ //
+ CTEInterlockedIncrementLong(&pAddress->RefCount);
+
+ if (!IsListEmpty(&pAddress->ClientHead))
+ {
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ *pBytesTaken = lDgramHdrSize;
+
+ //
+ // Check if there is more than one client that should receive this
+ // datagram. If so then pass down a new buffer to get it and
+ // copy it to each client's buffer in the completion routine.
+ //
+
+ *ppRcvBuffer = NULL;
+ MoreClients = FALSE;
+ *ppClientList = NULL;
+
+ pHead = &pAddress->ClientHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ PTDI_IND_RECEIVE_DATAGRAM EvRcvDgram;
+ PVOID RcvDgramEvContext;
+ PLIST_ENTRY pRcvEntry;
+ tRCVELE *pRcvEle;
+ ULONG MaxLength;
+ PLIST_ENTRY pSaveEntry;
+
+ pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
+
+ // this client must be registered against this adapter to
+ // get the data
+ //
+ if (!(pClientEle->pDeviceContext->AdapterNumber & AdapterNumber))
+ {
+ pEntry = pEntry->Flink;
+ continue;
+ }
+
+#ifdef VXD
+ //
+ // Move all of the RcvAnyFromAny Datagrams to this client's
+ // RcvDatagram list so they will be processed along with the
+ // outstanding datagrams for this client if this isn't a
+ // broadcast reception (RcvAnyFromAny dgrams
+ // don't receive broadcasts). The first client will
+ // empty the list, which is ok.
+ //
+ if ( *pName != '*' )
+ {
+ PLIST_ENTRY pDGEntry ;
+ while ( !IsListEmpty( &pDeviceContext->RcvDGAnyFromAnyHead ))
+ {
+ pDGEntry = RemoveHeadList(&pDeviceContext->RcvDGAnyFromAnyHead) ;
+ InsertTailList( &pClientEle->RcvDgramHead, pDGEntry ) ;
+ }
+ }
+#endif
+
+ // check for datagrams posted to this name, and if not call
+ // the recv event handler. NOTE: this assumes that the clients
+ // use posted recv buffer OR and event handler, but NOT BOTH.
+ // If two clients open the same name, one with a posted rcv
+ // buffer and another with an event handler, the one with the
+ // event handler will NOT get the datagram!
+ //
+ if (!IsListEmpty(&pClientEle->RcvDgramHead))
+ {
+ MaxLength = 0;
+ pSaveEntry = pEntry;
+ //
+ // go through all clients finding one that has a large
+ // enough buffer
+ //
+ while (pEntry != pHead)
+ {
+ pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
+
+ if (IsListEmpty(&pClientEle->RcvDgramHead))
+ {
+ continue;
+ }
+
+ pRcvEntry = pClientEle->RcvDgramHead.Flink;
+ pRcvEle = CONTAINING_RECORD(pRcvEntry,tRCVELE,Linkage);
+
+ if (pRcvEle->RcvLength >= BytesAvailable)
+ {
+ pSaveEntry = pEntry;
+ break;
+ }
+ else
+ {
+ // keep the maximum rcv length around incase none
+ // is large enough
+ //
+ if (pRcvEle->RcvLength > MaxLength)
+ {
+ pSaveEntry = pEntry;
+ MaxLength = pRcvEle->RcvLength;
+ }
+
+ pEntry = pEntry->Flink;
+ }
+
+ }
+
+ //
+ // Get the buffer off the list
+ //
+ pClientEle = CONTAINING_RECORD(pSaveEntry,tCLIENTELE,Linkage);
+
+ pRcvEntry = RemoveHeadList(&pClientEle->RcvDgramHead);
+
+ *ppRcvBuffer = pRcvEle->pIrp;
+#ifdef VXD
+ ASSERT( pDgram->SrcName.NameLength <= NETBIOS_NAME_SIZE*2) ;
+ LocStatus = ConvertToAscii(
+ (PCHAR)&pDgram->SrcName,
+ pDgram->SrcName.NameLength+1,
+ ((NCB*)*ppRcvBuffer)->ncb_callname,
+ &pScope,
+ &uLength);
+
+ if ( !NT_SUCCESS(LocStatus) )
+ {
+ DbgPrint("ConvertToAscii failed\r\n") ;
+ }
+#else //VXD
+
+ //
+ // put the source of the datagram into the return
+ // connection info structure.
+ //
+ if (pRcvEle->ReturnedInfo)
+ {
+ UCHAR pSrcName[NETBIOS_NAME_SIZE];
+
+ Offset = FIELD_OFFSET(tDGRAMHDR,SrcName.NetBiosName[0]);
+ LocStatus = ConvertToAscii(
+ (PCHAR)&pDgram->SrcName,
+ BytesIndicatedOrig-Offset,
+ pSrcName,
+ &pScope,
+ &uLength);
+
+ if (pRcvEle->ReturnedInfo->RemoteAddressLength >=
+ sizeof(TA_NETBIOS_ADDRESS))
+ {
+ TdiBuildNetbiosAddress(pSrcName,
+ FALSE,
+ pRcvEle->ReturnedInfo->RemoteAddress);
+ }
+
+ }
+#endif
+
+#ifndef VXD
+ //
+ // Null out the cancel routine since we are passing the
+ // irp to the transport
+ //
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine(pRcvEle->pIrp,NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+#endif
+ CTEMemFree((PVOID)pRcvEle);
+
+ if (pAddress->MultiClients)
+ {
+ // the multihomed host always passes the above test
+ // so we need a more discerning test for it.
+ if (!NbtConfig.MultiHomed)
+ {
+ // if the list is more than one on it,
+ // then there are several clients waiting
+ // to receive this datagram, so pass down a buffer to
+ // get it.
+ //
+ MoreClients = TRUE;
+ status = STATUS_SUCCESS;
+
+ UsingClientBuffer = TRUE;
+
+ // this break will jump down below where we check if
+ // MoreClients = TRUE
+ break;
+ }
+ else
+ {
+
+ }
+
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+
+ NbtDereferenceAddress(pAddress);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ status = STATUS_SUCCESS;
+
+ //
+ // jump to end of while to check if we need to buffer
+ // the datagram source address
+ // in the remote hash table
+ //
+ break;
+ }
+#ifdef VXD
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ NbtDereferenceAddress(pAddress);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ break;
+ }
+#endif
+
+
+#ifndef VXD
+ EvRcvDgram = pClientEle->evRcvDgram;
+ RcvDgramEvContext = pClientEle->RcvDgramEvContext;
+
+ // don't want to call the default handler since it just
+ // returns data not accepted
+ if (pClientEle->evRcvDgram != TdiDefaultRcvDatagramHandler)
+ {
+ // finally found a real event handler set by a client
+
+ if (pAddress->MultiClients)
+// if (pEntry->Flink != pHead)
+ {
+ // if the next element in the list is not the head
+ // of the list then there are several clients waiting
+ // to receive this datagram, so pass down a buffer to
+ // get it.
+ //
+ MoreClients = TRUE;
+ UsingClientBuffer = FALSE;
+ status = STATUS_SUCCESS;
+
+ break;
+
+ }
+
+ //
+ // make up an address datastructure - subtracting the
+ // number of bytes skipped from the total length so
+ // convert to Ascii can not bug chk on bogus names.
+ //
+ {
+ ULONG NumAddrs;
+
+ if (pClientEle->ExtendedAddress) {
+ NumAddrs = 2;
+ } else {
+ NumAddrs = 1;
+ }
+
+ LocStatus = MakeRemoteAddressStructure(
+ (PCHAR)&pDgram->SrcName.NameLength,
+ pSourceAddr,
+ BytesIndicatedOrig - FIELD_OFFSET(tDGRAMHDR,SrcName.NameLength),
+ &pRemoteAddress, // the end of the pdu.
+ &RemoteAddressLength,
+ NumAddrs);
+ }
+ pClientEle->RefCount++;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ if (!NT_SUCCESS(LocStatus))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ pIrp = NULL;
+ lClientBytesTaken = 0;
+ LocStatus = (*EvRcvDgram)(RcvDgramEvContext,
+ RemoteAddressLength,
+ pRemoteAddress,
+ OptionsLength,
+ pOptions,
+ ReceiveDatagramFlags,
+ BytesIndicated,
+ BytesAvailable,
+ &lClientBytesTaken,
+ pTsdu,
+ &pIrp);
+
+
+ CTEMemFree((PVOID)pRemoteAddress);
+
+ NbtDereferenceClient(pClientEle);
+
+ NbtDereferenceAddress(pAddress);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ if (!pIrp)
+ {
+ status = STATUS_DATA_NOT_ACCEPTED;
+ }
+ else
+ {
+
+ // the client has passed back an irp so pass it
+ // on the transport
+
+ *pBytesTaken += lClientBytesTaken;
+ *ppRcvBuffer = pIrp;
+
+ status = STATUS_SUCCESS;
+ break;
+ }
+
+ }
+
+#endif //!VXD
+
+ // go to the next client in the list
+ pEntry = pEntry->Flink;
+
+ }// of While
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // Cache the source address in the remote hash table so that
+ // this node can send back to the source even if the name
+ // is not yet in the name server yet. (only if not on the
+ // same subnet)
+ //
+ if ((pDgram->MsgType != BROADCAST_DGRAM))
+ {
+ ULONG SrcAddress;
+ PTRANSPORT_ADDRESS pSourceAddress;
+ ULONG SubnetMask;
+
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSourceAddr;
+ SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
+ SubnetMask = pDeviceContext->SubnetMask;
+ //
+ // - cache only if from off the subnet
+ // - cache if not sent to 1E,1D,01 name and not from ourselves
+ //
+ // don't cache dgrams from ourselves, or datagrams to the
+ // 1E name, 1D, or 01.
+ //
+ if (((SrcAddress & SubnetMask) !=
+ (pDeviceContext->IpAddress & SubnetMask))
+ ||
+ (
+ (pName[NETBIOS_NAME_SIZE-1] != 0x1E) &&
+ (pName[NETBIOS_NAME_SIZE-1] != 0x1D) &&
+ (pName[NETBIOS_NAME_SIZE-1] != 0x01) &&
+ (!SrcIsUs(SrcAddress))))
+ {
+ AddToRemoteHashTbl(pDgram,BytesIndicatedOrig,pDeviceContext);
+ }
+ }
+
+ // alloc a block of memory to track where we are in the list
+ // of clients so completionrcvdgram can send the dgram to the
+ // other clients too.
+ //
+ if (MoreClients)
+ {
+ tCLIENTLIST *pClientList;
+
+ pClientList = (tCLIENTLIST *)NbtAllocMem(sizeof(tCLIENTLIST),NBT_TAG('4'));
+ if (pClientList)
+ {
+ //
+ // Set fProxy field to FALSE since the client list is for
+ // real as versus the PROXY case
+ //
+ pClientList->fProxy = FALSE;
+
+ // save some context information so we can pass the
+ // datagram to the clients - none of the clients have
+ // recvd the datagram yet.
+ //
+ *ppClientList = (PVOID)pClientList;
+ pClientList->pAddress = pAddress;
+ pClientList->pClientEle = pClientEle; // used for VXD case
+ pClientList->fUsingClientBuffer = UsingClientBuffer;
+ pClientList->ReceiveDatagramFlags = ReceiveDatagramFlags;
+
+ // make up an address datastructure
+ LocStatus = MakeRemoteAddressStructure(
+ (PCHAR)&pDgram->SrcName.NameLength,
+ 0,
+ BytesIndicatedOrig -FIELD_OFFSET(tDGRAMHDR,SrcName.NameLength),// set a max number of bytes so we don't go beyond
+ &pRemoteAddress, // the end of the pdu.
+ &RemoteAddressLength,
+ 1);
+ if (NT_SUCCESS(LocStatus))
+ {
+ pClientList->pRemoteAddress = pRemoteAddress;
+ pClientList->RemoteAddressLength = RemoteAddressLength;
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ *ppClientList = NULL;
+ CTEMemFree(pClientList);
+ status = STATUS_DATA_NOT_ACCEPTED;
+
+ }
+ }
+ else
+ status = STATUS_DATA_NOT_ACCEPTED;
+ }
+
+ }
+ else
+ {
+ pAddress->RefCount--;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = STATUS_DATA_NOT_ACCEPTED;
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:No client attached to the Address %16.16s<%X>\n",
+ pAddress->pNameAddr->Name,pAddress->pNameAddr->Name[15]));
+ }
+
+ }
+ else
+ {
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = STATUS_DATA_NOT_ACCEPTED;
+ }
+
+#ifdef PROXY_NODE
+ IF_PROXY(NodeType)
+ {
+ ULONG SrcAddress;
+ PTRANSPORT_ADDRESS pSourceAddress;
+ ULONG SubnetMask;
+
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSourceAddr;
+ SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
+
+ //
+ // check name in the remote name table. If it is there, it is
+ // an internet group and is in the resolved state, send the
+ // datagram to all the members except self. If it is in the
+ // resolving state, just return. The fact that we got a
+ // datagram send for an internet group name still in the
+ // resolving state indicates that there is a DC on the subnet
+ // that responded to the query for the group received
+ // earlier. This means that the DC will respond (unless it
+ // goes down) to this datagram send. If the DC is down, the
+ // client node will retry.
+ //
+ // Futures: Queue the Datagram if the name is in the resolving
+ // state.
+ //
+ // If Flags are zero then it is a non fragmented Bnode send. There
+ // is not point in doing datagram distribution for P,M,or H nodes
+ // can they can do their own.
+ //
+ if (((pDgram->Flags & SOURCE_NODE_MASK) == 0) &&
+ (pName[0] != '*') &&
+ (!SrcIsUs(SrcAddress)))
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ pNameAddr = (tNAMEADDR *)FindName(
+ NBT_REMOTE,
+ pName,
+ pScope,
+ &RetNameType
+ );
+
+ if (pNameAddr)
+ {
+ //
+ // We have the name in the RESOLVED state.
+ //
+ //
+ // If the name is an internet group, do datagram distribution
+ // function
+ // Make sure we don't distribute a datagram that has been
+ // sent to us by another proxy. In other words, distribute
+ // the datagram only if we got it first-hand from original node
+ //
+ if ( (pNameAddr->NameTypeState & NAMETYPE_INET_GROUP) &&
+ ((((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr) == pDgram->SrcIpAddr) )
+ {
+ //
+ // If BytesAvailable != BYtesIndicated, it means that
+ // that we don't have the entire datagram. We need to
+ // get it
+ if (BytesAvailableOrig != BytesIndicatedOrig)
+ {
+ tCLIENTLIST *pClientList;
+
+ //
+ // Do some simulation to fake the caller of this fn
+ // (TdiRcvDatagramHndlr) into thinking that there are
+ // multiple clients. This will result in
+ // TdiRcvDatagramHndlr function getting all bytes
+ // available from TDI and calling
+ // ProxyDoDgramDist to do the datagram distribution
+ //
+ pClientList =
+ (tCLIENTLIST *)NbtAllocMem(sizeof(tCLIENTLIST),NBT_TAG('5'));
+
+ if (pClientList)
+ {
+ //
+ // save some context information in the Client List
+ // data structure
+ //
+ *ppClientList = (PVOID)pClientList;
+ //
+ // Set fProxy field to TRUE since the client list
+ // not for real
+ //
+ pClientList->fProxy = TRUE;
+
+ //
+ // Make use of the following fields to pass the
+ // information we would need in the
+ // CompletionRcvDgram
+ //
+ pClientList->pAddress = (tADDRESSELE *)pNameAddr;
+ pClientList->pRemoteAddress = pDeviceContext;
+
+ //
+ // Increment the reference count so that this name
+ // does not disappear on us after we free the
+ // spin lock. DgramSendCleanupTracker called from
+ // SendDgramCompletion in Name.c will
+ // decrement the count
+ //
+ pNameAddr->RefCount++;
+ status = STATUS_DATA_NOT_ACCEPTED;
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ } // end of if (we do not have the entire datagram)
+ else
+ {
+ //
+ // Increment the reference count so that this name
+ // does not disappear on us after we free the spin lock.
+ //
+ // DgramSendCleanupTracker will decrement the count
+ //
+ pNameAddr->RefCount++;
+ //
+ //We have the entire datagram.
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ (VOID)ProxyDoDgramDist(
+ pDgram,
+ BytesIndicatedOrig,
+ pNameAddr,
+ pDeviceContext
+ );
+
+ status = STATUS_DATA_NOT_ACCEPTED;
+ }
+
+ } // end of if (if name is an internet group name)
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ } // end of if (Name is there in remote hash table)
+ else
+ {
+ tNAMEADDR *pResp;
+
+ //
+ // the name is not in the cache, so try to get it from
+ // WINS
+ //
+ status = FindOnPendingList(pName,NULL,TRUE,NETBIOS_NAME_SIZE,&pResp);
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // cache the name and contact the name
+ // server to get the name to IP mapping
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = RegOrQueryFromNet(
+ FALSE, //means it is a name query
+ pDeviceContext,
+ NULL,
+ uLength,
+ pName,
+ pScope);
+
+ }
+ else
+ {
+ //
+ // the name is on the pending list doing a name query
+ // now, so ignore this name query request
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ }
+
+ status = STATUS_DATA_NOT_ACCEPTED;
+ }
+ }
+ }
+ END_PROXY
+#endif
+
+ } // end of a directed or broadcast datagram
+ else
+ {
+ if (pDgram->MsgType == ERROR_DGRAM)
+ {
+ KdPrint(("Nbt:ERROR Datagram received, Error Code = %X\n",
+ ((tDGRAMERROR *)pDgram)->ErrorCode));
+ }
+ else
+ {
+ KdPrint(("Nbt:Dgram Rcvd, not expecting..., MsgType = %X\n",
+ pDgram->MsgType));
+
+ }
+ }
+ return(status);
+}
+
+#ifdef PROXY_NODE
+//----------------------------------------------------------------------------
+NTSTATUS
+ProxyDoDgramDist(
+ IN tDGRAMHDR UNALIGNED *pDgram,
+ IN DWORD DgramLen,
+ IN tNAMEADDR *pNameAddr,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ ppRcvbuffer will contain the IRP/NCB if only one client is listening,
+ NULL if multiple clients are listening
+ ppClientList will contain the list clients that need to be completed,
+ NULL if only one client is listening
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+Called By:
+
+ DgramHdlrNotOs, CompletionRcvDgram in tdihndlr.c
+
+--*/
+{
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ tDGRAMHDR *pMyBuff;
+
+ //
+ // get a buffer for tracking Dgram Sends
+ //
+ pTracker = NbtAllocTracker();
+ if (!pTracker)
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ NbtDereferenceName(pNameAddr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // Allocate a buffer and copy the contents of the datagram received
+ // into it. We do this because SndDgram may not have finished by the
+ // time we return.
+ //
+ pMyBuff = (tDGRAMHDR *)NbtAllocMem(DgramLen,NBT_TAG('6'));
+ if ( !pMyBuff )
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ NbtDereferenceName(pNameAddr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ CTEFreeMem(pTracker) ;
+ return STATUS_INSUFFICIENT_RESOURCES ;
+ }
+
+ CTEMemCopy(pMyBuff, (PUCHAR)pDgram, DgramLen);
+
+ //
+ // fill in the tracker data block
+ // note that the passed in transport address must stay valid till this
+ // send completes
+ //
+ CHECK_PTR(pTracker);
+ pTracker->SendBuffer.pDgramHdr = (PVOID)pMyBuff;
+ pTracker->SendBuffer.HdrLength = DgramLen;
+ pTracker->SendBuffer.pBuffer = NULL;
+ pTracker->SendBuffer.Length = 0;
+ pTracker->pNameAddr = pNameAddr;
+ pTracker->pDeviceContext = (PVOID)pDeviceContext;
+ pTracker->p1CNameAddr = NULL;
+ //
+ // so DgramSendCleanupTracker does not decrement the bytes allocated
+ // to dgram sends, since we did not increment the count when we allocated
+ // the dgram buffer above.
+ //
+ pTracker->AllocatedLength = 0;
+
+ pTracker->pClientIrp = NULL;
+ pTracker->pClientEle = NULL;
+
+ KdPrint(("ProxyDoDgramDist: Name is %16.16s(%X)\n", pNameAddr->Name,
+ pNameAddr->Name[15]));
+
+ //
+ // Send the datagram to each IP address in the Internet group
+ //
+ //
+ DatagramDistribution(pTracker,pNameAddr);
+
+ return(STATUS_SUCCESS);
+}
+#endif
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NameSrvHndlrNotOs (
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameSrv,
+ IN ULONG uNumBytes,
+ IN BOOLEAN fBroadcast
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive datagram event indication handler.
+
+ It is called when an a datgram arrives from the network. The code
+ checks the type of datagram and then tries to route the datagram to
+ the correct destination on the node.
+
+ This procedure is called with the spin lock held on pDeviceContext.
+
+Arguments:
+
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+ USHORT OpCodeFlags;
+ NTSTATUS status;
+
+ // it appears that streams can pass a null data pointer some times
+ // and crash nbt...and zero length for the bytes
+ if (uNumBytes < sizeof(ULONG))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ OpCodeFlags = pNameSrv->OpCodeFlags;
+
+ //Pnodes always ignore Broadcasts since they only talk to the NBNS unless
+ // this node is also a proxy
+ if ( ( ((NodeType) & PNODE)) && !((NodeType) & PROXY) )
+ {
+ if (OpCodeFlags & FL_BROADCAST)
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ }
+
+
+ // decide what type of name service packet it is by switching on the
+ // NM_Flags portion of the word
+ switch (OpCodeFlags & NM_FLAGS_MASK)
+ {
+ case OP_QUERY:
+ status = QueryFromNet(
+ pDeviceContext,
+ pSrcAddress,
+ pNameSrv,
+ uNumBytes,
+ OpCodeFlags,
+ fBroadcast);
+ break;
+
+ case OP_REGISTRATION:
+ //
+ // we can get either a registration request or a response
+ //
+ // is this a request or a response? - if bit is set its a Response
+
+ if (OpCodeFlags & OP_RESPONSE)
+ {
+ // then this is a response to a previous reg. request
+ status = RegResponseFromNet(
+ pDeviceContext,
+ pSrcAddress,
+ pNameSrv,
+ uNumBytes,
+ OpCodeFlags);
+ }
+ else
+ {
+ //
+ // check if someone else is trying to register a name
+ // owned by this node. Pnodes rely on the Name server to
+ // handle this...hence the check for Pnode
+ //
+ if (!(NodeType & PNODE))
+ {
+ status = CheckRegistrationFromNet(pDeviceContext,
+ pSrcAddress,
+ pNameSrv,
+ uNumBytes);
+ }
+ }
+ break;
+
+ case OP_RELEASE:
+ //
+ // handle other nodes releasing their names by deleting any
+ // cached info
+ //
+ status = NameReleaseFromNet(
+ pDeviceContext,
+ pSrcAddress,
+ pNameSrv,
+ uNumBytes);
+ break;
+
+ case OP_WACK:
+ if (!(NodeType & BNODE))
+ {
+ // the TTL in the WACK tells us to increase our timeout
+ // of the corresponding request, which means we must find
+ // the transaction
+ status = WackFromNet(pDeviceContext,
+ pSrcAddress,
+ pNameSrv,
+ uNumBytes);
+ }
+ break;
+
+ case OP_REFRESH:
+ case OP_REFRESH_UB:
+
+ break;
+
+ default:
+ IF_DBG(NBT_DEBUG_HNDLRS)
+ KdPrint(("NBT: Unknown Name Service Pdu type OpFlags = %X\n",
+ OpCodeFlags));
+ break;
+
+
+ }
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+}
+
+VOID
+DoNothingComplete (
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is the completion routine for TdiDisconnect while we are
+ retrying connects. It does nothing.
+
+ This is required because you can't have a NULL TDI completion routine.
+
+--*/
+{
+ return ;
+}
diff --git a/private/ntos/nbt/nbt/inbound.c b/private/ntos/nbt/nbt/inbound.c
new file mode 100644
index 000000000..6c0430d89
--- /dev/null
+++ b/private/ntos/nbt/nbt/inbound.c
@@ -0,0 +1,4118 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Inbound.c
+
+Abstract:
+
+
+ This file implements the inbound name service pdu handling. It handles
+ name queries from the network and Registration responses from the network.
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+#include "ctemacro.h"
+
+NTSTATUS
+DecodeNodeStatusResponse(
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN ULONG Length,
+ IN PUCHAR pName,
+ IN ULONG lNameSize,
+ IN ULONG SrcIpAddress
+ );
+
+NTSTATUS
+ExtractServerName(
+ IN tNODESTATUS UNALIGNED *pNodeStatus,
+ IN PVOID pClientContext,
+ IN ULONG IpAddress
+ );
+
+NTSTATUS
+SendNodeStatusResponse(
+ IN tNAMEHDR UNALIGNED *pInNameHdr,
+ IN ULONG Length,
+ IN PUCHAR pName,
+ IN ULONG lNameSize,
+ IN ULONG SrcIpAddress,
+ IN USHORT SrcPort,
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+NTSTATUS
+UpdateNameState(
+ IN tADDSTRUCT UNALIGNED *pAddrStruct,
+ IN tNAMEADDR *pNameAddr,
+ IN ULONG Length,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN BOOLEAN SrcIsNameServer,
+ IN tDGRAM_SEND_TRACKING *Context,
+ IN CTELockHandle OldIrq1
+ );
+NTSTATUS
+ChkIfValidRsp(
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN tNAMEADDR *pNameAddr
+ );
+
+VOID
+CopyNodeStatusResponse(
+ IN PVOID pContext
+ );
+
+NTSTATUS
+ChooseBestIpAddress(
+ IN tADDSTRUCT UNALIGNED *pAddrStruct,
+ IN ULONG Len,
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT tDGRAM_SEND_TRACKING *pTracker,
+ OUT PULONG pIpAddress,
+ IN BOOLEAN fTryAllAddr
+ );
+
+USHORT
+GetNbFlags(
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN ULONG lNameSize
+ );
+
+VOID
+PrintHexString(
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN ULONG lNumBytes
+ );
+
+ULONG
+MakeList(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN ULONG CountAddrs,
+ IN tADDSTRUCT UNALIGNED *pAddrStruct,
+ IN PULONG AddrArray,
+ IN ULONG SizeOfAddrArray,
+ IN BOOLEAN IsSubnetMatch
+ );
+
+
+#if DBG
+#define KdPrintHexString(pHdr,NumBytes) \
+ PrintHexString(pHdr,NumBytes)
+#else
+#define KdPrintHexString(pHdr,NumBytes)
+#endif
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, CopyNodeStatusResponse)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+QueryFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN USHORT OpCodeFlags,
+ IN BOOLEAN fBroadcast
+ )
+/*++
+
+Routine Description:
+
+ This routine handles both name query requests and responses. For Queries
+ it checks if the name is registered on this node. If this node is a proxy
+ it then forwards a name query onto the Name Server, adding the name to the
+ remote proxy cache...
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not - failure means no response to net
+
+--*/
+{
+ NTSTATUS status;
+ LONG lNameSize;
+ CHAR pName[NETBIOS_NAME_SIZE];
+ PUCHAR pScope;
+ tNAMEADDR *pResp;
+ tTIMERQENTRY *pTimer;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+ PTRANSPORT_ADDRESS pSourceAddress;
+ ULONG SrcAddress;
+ CTELockHandle OldIrq1;
+ tQUERYRESP UNALIGNED *pQuery;
+ USHORT SrcPort;
+ ULONG IpAddr;
+
+
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
+ SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
+
+
+ SrcPort = ntohs(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->sin_port);
+
+
+#ifdef VXD
+ //
+ // is this a response from a DNS server? if yes then handle it
+ // appropriately
+ //
+ if (SrcPort == NBT_DNSSERVER_UDP_PORT)
+ {
+ USHORT TransactionId;
+ TransactionId = ntohs(pNameHdr->TransactId);
+ if ( TransactionId >= DIRECT_DNS_NAME_QUERY_BASE )
+ {
+ ProcessDnsResponseDirect( pDeviceContext,
+ pSrcAddress,
+ pNameHdr,
+ lNumBytes,
+ OpCodeFlags );
+ }
+ else
+ {
+ ProcessDnsResponse( pDeviceContext,
+ pSrcAddress,
+ pNameHdr,
+ lNumBytes,
+ OpCodeFlags );
+ }
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+#endif
+
+ //
+ // check the pdu size for errors - be sure the name is long enough for
+ // the scope on this machine.
+ //
+ if (lNumBytes < (NBT_MINIMUM_QUERY + NbtConfig.ScopeLength - 1))
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Name Query PDU TOO short = %X,Src= %X\n",lNumBytes,SrcAddress));
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+
+ // get the name out of the network pdu and pass to routine to check
+ // local table *TODO* this assumes just one name in the Query response...
+ status = ConvertToAscii(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ lNumBytes,
+ pName,
+ &pScope,
+ &lNameSize);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+
+ // check if this is a request or a response pdu
+
+ //
+ // *** RESPONSE ***
+ //
+ if (OpCodeFlags & OP_RESPONSE)
+ {
+
+ //
+ // check the pdu size for errors
+ //
+ if (lNumBytes < (NBT_MINIMUM_QUERYRESPONSE + NbtConfig.ScopeLength -1))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ if (!(OpCodeFlags & FL_AUTHORITY))
+ {
+ //
+ // This is a redirect response telling us to go to another
+ // name server, which we do not support, so just return
+ // *TODO*
+ //
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+
+ //
+ // check if this is a node status request, since is looks very similar
+ // to a name query, except that the NBSTAT field is 0x21 instead of
+ // 0x20
+ //
+ pQuery = (tQUERYRESP *)&pNameHdr->NameRR.NetBiosName[lNameSize];
+
+ if ( ((PUCHAR)pQuery)[1] == QUEST_STATUS )
+ {
+ status = DecodeNodeStatusResponse(pNameHdr,
+ lNumBytes,
+ pName,
+ lNameSize,
+ SrcAddress);
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ //
+ // call this routine to find the name, since it does not interpret the
+ // state of the name as does FindName()
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ status = FindOnPendingList(pName,pNameHdr,FALSE,NETBIOS_NAME_SIZE,&pResp);
+
+ if (NT_SUCCESS(status))
+ {
+
+ pQuery = (tQUERYRESP *)&pNameHdr->NameRR.NetBiosName[lNameSize];
+
+
+ // remove any timer block and call the completion routine
+ if ((pTimer = pResp->pTimer))
+ {
+ USHORT Flags;
+ tDGRAM_SEND_TRACKING *pTracker;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pTimer->Context;
+
+ //
+ // If this is not a response to a request sent by the PROXY code
+ // and
+ // MSNode && Error Response code && Src is NameServer && Currently
+ // resolving with the name server, then switch to broadcast
+ // ... or if it is a Pnode or Mnode and EnableLmHost or
+ // ResolveWithDns is on, then
+ // let the timer expire again, and try Lmhost.
+ //
+ if (
+ #ifdef PROXY_NODE
+ !pResp->fProxyReq &&
+ #endif
+ (IS_NEG_RESPONSE(OpCodeFlags)))
+
+ {
+
+ Flags = pTracker->Flags;
+
+ if ((NodeType & (PNODE | MNODE | MSNODE)) &&
+ (Flags & (NBT_NAME_SERVER | NBT_NAME_SERVER_BACKUP)))
+ {
+ // this should let MsnodeCompletion try the
+ // backup WINS or broadcast
+ // processing when the timer timesout.
+ //
+ pTimer->Retries = 1;
+ pTracker->Flags |= WINS_NEG_RESPONSE;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ else
+ {
+ tDEVICECONTEXT *pDevContext;
+
+ //
+ // save the devicecontext since the call to StopTimer could
+ // free pTracker
+ //
+ pDevContext = pTracker->pDeviceContext;
+ //
+ // this routine puts the timer block back on the timer Q, and
+ // handles race conditions to cancel the timer when the timer
+ // is expiring.
+ //
+ status = StopTimer(pTimer,&pClientCompletion,&Context);
+ LOCATION(0x42);
+ //
+ // we need to synchronize removing the name from the list
+ // with MsNodeCompletion
+ //
+ if (pClientCompletion)
+ {
+ LOCATION(0x41);
+ //
+ // Remove from the pending list
+ RemoveEntryList(&pResp->Linkage);
+ InitializeListHead(&pResp->Linkage);
+
+ CHECK_PTR(pResp);
+ pResp->pTimer = NULL;
+
+ // check the name query response ret code to see if the name
+ // query succeeded or not.
+ if (IS_POS_RESPONSE(OpCodeFlags))
+ {
+ BOOLEAN ResolvedByWins;
+
+ LOCATION(0x40);
+ //
+ // Keep track of how many names are resolved by WINS and
+ // keep a list of names not resolved by WINS
+ //
+ if (!(ResolvedByWins = SrcIsNameServer(SrcAddress,SrcPort)))
+ {
+ SaveBcastNameResolved(pName);
+ }
+
+ IncrementNameStats(NAME_QUERY_SUCCESS,
+ ResolvedByWins);
+
+ #ifdef PROXY_NODE
+ // Set flag if the node queries is a PNODE
+ //
+ IF_PROXY(NodeType)
+ {
+ pResp->fPnode =
+ (pNameHdr->NameRR.NetBiosName[lNameSize+QUERY_NBFLAGS_OFFSET]
+ & NODE_TYPE_MASK) == PNODE_VAL_IN_PKT;
+
+ IF_DBG(NBT_DEBUG_PROXY)
+ KdPrint(("QueryFromNet: POSITIVE RESPONSE to name query - %16.16s(%X)\n", pResp->Name, pResp->Name[15]));
+ }
+
+ #endif
+
+ pResp->AdapterMask |= pDevContext->AdapterNumber;
+
+ IpAddr = ((tADDSTRUCT *)&pQuery->Flags)->IpAddr;
+ status = UpdateNameState((tADDSTRUCT *)&pQuery->Flags,
+ pResp,
+ lNumBytes -((ULONG)&pQuery->Flags - (ULONG)pNameHdr),
+ pDeviceContext,
+ SrcIsNameServer(SrcAddress,SrcPort),
+ (tDGRAM_SEND_TRACKING *)Context,
+ OldIrq1);
+ //
+ // since pResp can be freed in UpdateNameState do not
+ // access it here
+ //
+ pResp = NULL;
+ // status = STATUS_SUCCESS;
+ }
+ else // negative query response received
+ {
+
+ LOCATION(0x3f);
+ //
+ // Release the name. It will get dereferenced by the
+ // cache timeout function (RemoteHashTimeout).
+ //
+ pResp->NameTypeState &= ~NAME_STATE_MASK;
+ pResp->NameTypeState |= STATE_RELEASED;
+ //
+ // the proxy maintains a negative cache of names that
+ // do not exist in WINS. These are timed out by
+ // the remote hash timer just as the resolved names
+ // are timed out.
+ //
+ if (!(NodeType & PROXY))
+ {
+ NbtDereferenceName(pResp);
+ }
+ else
+ {
+ //
+ // Add to cache as negative name entry
+ //
+ status = AddRecordToHashTable(pResp,
+ NbtConfig.pScope);
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // this could delete the name so do not reference
+ // after this point
+ //
+ NbtDereferenceName(pResp);
+ }
+ }
+
+ status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ //
+ // Set the backup name server to be the main name server
+ // since we got a response from it.
+ //
+ if ( ((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr
+ == (ULONG)(htonl(pDeviceContext->lBackupServer)))
+ {
+ // switching the backup and the primary nameservers in
+ // the config data structure since we got a name
+ // registration response from the backup
+ //
+ SwitchToBackup(pDeviceContext);
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+//
+// chicago only has 4k of stack (yes, it's the operating system of 1995)
+// schedule an event to make this tcp connection later to reduce stack usage
+//
+#ifdef VXD
+ (void) CTEQueueForNonDispProcessing(
+ (tDGRAM_SEND_TRACKING *)Context,
+ (PVOID)status,
+ pClientCompletion,
+ DelayedSessEstablish,
+ pDeviceContext);
+#else
+ // the completion routine has not run yet, so run it
+ //
+
+ //
+ // If pending is returned, we have submitted the check-for-addr request to lmhsvc.
+ //
+ if (status != STATUS_PENDING) {
+ CompleteClientReq(pClientCompletion,
+ (tDGRAM_SEND_TRACKING *)Context,
+ status);
+ }
+#endif
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ }
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ }
+ else
+ if (!NbtConfig.MultiHomed)
+ {
+
+ //
+ // it is possible for two multihomed machines connected on two subnets
+ // to respond on both subnets to a name query. Therefore the querying
+ // multihomed machine will ultimately receive two name query responses
+ // each with a different ip address and think that a name conflict has
+ // occurred when it hasn't. There is no way to detect this case
+ // so just disable the conflict detection code below. Conflicts will
+ // still be detected by WINS and by the node owning the name if someone
+ // else tries to get the name, but conflicts will no longer be detected
+ // by third parties that have the name in their cache.
+ //
+ //
+ // The name is not in the NameQueryPending list, so check the
+ // remote table.
+ //
+
+ //
+ // This code implements a Conflict timer for name
+ // queries. Look at name query response, and then send
+ // name conflict demands to the subsequent responders.
+ // There is no timer involved, and this node will always respond
+ // negatively to name query responses sent to it, for names
+ // it has in its remote cache, if the timer has been stopped.
+ // ( meaning that one response has been successfully received ).
+
+
+ status = FindInHashTable(NbtConfig.pRemoteHashTbl,
+ pName,
+ pScope,
+ &pResp);
+
+ // check the src IP address and compare it to the one in the
+ // remote hash table
+ // Since it is possible for the name server to send a response
+ // late, do not accidently respond to those as conflicts.
+ // Since a bcast query of a group name will generally result in
+ // multiple responses, each with a different address, ignore
+ // this case.
+ // Also, ignore if the name is a preloaded lmhosts entry (though
+ // can't think of an obvious case where we would receive a response
+ // when a name is preloaded!)
+ //
+ if (NT_SUCCESS(status) &&
+ !(pResp->NameTypeState & PRELOADED)
+ &&
+ (SrcAddress != pResp->IpAddress)
+ &&
+ (pResp->NameTypeState & NAMETYPE_UNIQUE)
+ &&
+ (pResp->NameTypeState & STATE_RESOLVED)
+ &&
+ ((SrcAddress != pDeviceContext->lNameServerAddress)
+ &&
+ (SrcAddress != pDeviceContext->lBackupServer)))
+ {
+ //
+ // a different node is responding to the name query
+ // so tell them to buzz off.
+ //
+ status = UdpSendResponse(
+ lNameSize,
+ pNameHdr,
+ pResp,
+ (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
+ pDeviceContext,
+ CONFLICT_ERROR,
+ eNAME_REGISTRATION_RESPONSE,
+ OldIrq1);
+
+ //
+ // remove the name from the remote cache so the next time
+ // we need to talk to it we do a name query
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ // set the name to the released state so that multiple
+ // conflicting responses don't come in and decrement the
+ // reference count to zero - in the case where some other
+ // part of NBT is still using the name, that part of NBT
+ // should do the final decrement - i.e. a datagram send to this
+ // name.
+ pResp->NameTypeState &= ~NAME_STATE_MASK;
+ pResp->NameTypeState |= STATE_RELEASED;
+
+ //
+ // don't deref if someone is using it now...
+ //
+ if (pResp->RefCount == 1)
+ {
+ NbtDereferenceName(pResp);
+ }
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ }
+ else // *** REQUEST ***
+ {
+ NTSTATUS Locstatus;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ // call this routine
+ // to see if the name is in the local table.
+ //
+ status = FindInHashTable(NbtConfig.pLocalHashTbl,
+ pName,
+ pScope,
+ &pResp);
+
+ if (NT_SUCCESS(status) &&
+ ((pResp->NameTypeState & STATE_RESOLVED) ||
+ (pResp->NameTypeState & STATE_RESOLVING)))
+ {
+ //
+ // check if this is a node status request, since is looks very similar
+ // to a name query, except that the NBSTAT field is 0x21 instead of
+ // 0x20
+ //
+ pQuery = (tQUERYRESP *)&pNameHdr->NameRR.NetBiosName[lNameSize];
+ if ( ((PUCHAR)pQuery)[1] == QUEST_STATUS )
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ //
+ // Reply only if this was not broadcast to us.
+ //
+ if (!fBroadcast) {
+ Locstatus = SendNodeStatusResponse(pNameHdr,
+ lNumBytes,
+ pName,
+ lNameSize,
+ SrcAddress,
+ SrcPort,
+ pDeviceContext);
+ } else {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("NBT: Bcast nodestatus req.- dropped\n"));
+ }
+ }
+ else
+ {
+ //
+ // check if this message came from Us or it is not
+ // a broadcast since WINS on this machine could send it.
+ // Note: this check must be AFTER the check for a node status request
+ // since we can send node status requests to ourselves.
+ //
+ if (!SrcIsUs(SrcAddress) ||
+ (!(OpCodeFlags & FL_BROADCAST)
+#ifndef VXD
+ && pWinsInfo
+#endif
+ ) )
+ {
+ //
+ // build a positive name query response pdu
+ //
+ Locstatus = UdpSendResponse(
+ lNameSize,
+ pNameHdr,
+ pResp,
+ (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
+ pDeviceContext,
+ 0,
+ eNAME_QUERY_RESPONSE,
+ OldIrq1);
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ }
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ else
+ // Build a negative response if this query was directed rather than
+ // broadcast (since we do not want to Nack all broadcasts!)
+ if ( !(OpCodeFlags & FL_BROADCAST) )
+ {
+
+ // check that it is not a node status request...
+ //
+ pQuery = (tQUERYRESP *)&pNameHdr->NameRR.NetBiosName[lNameSize];
+ if ( ((PUCHAR)pQuery)[1] == QUEST_NETBIOS )
+ {
+ Locstatus = UdpSendResponse(
+ lNameSize,
+ pNameHdr,
+ NULL,
+ (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
+ pDeviceContext,
+ 0,
+ eNAME_QUERY_RESPONSE,
+ OldIrq1);
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ }
+
+#ifdef PROXY_NODE
+
+ //
+ // check if this message came from Us !! (and return if so)
+ //
+ if (SrcIsUs(SrcAddress))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ pQuery = (tQUERYRESP *)&pNameHdr->NameRR.NetBiosName[lNameSize];
+
+ IF_PROXY(NodeType)
+ {
+ // check that it is not a node status request...
+ if (((PUCHAR)pQuery)[1] == QUEST_NETBIOS )
+ {
+ //
+ // We have a broadcast name query request for a name that
+ // is not in our local name table. If we are a proxy we need
+ // to resolve the query if not already resolved and respond
+ // with the address(es) to the node that sent the query.
+ //
+ // Note: We will respond only if the address that the name
+ // resolves to is not on our subnet. For our own subnet addresses
+ // the node that has the address will respond.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ //
+ // call this routine which looks for names without regard
+ // to their state
+ //
+ status = FindInHashTable(NbtConfig.pRemoteHashTbl,
+ pName,
+ pScope,
+ &pResp);
+
+ if (!NT_SUCCESS(status))
+ {
+ status = FindOnPendingList(pName,pNameHdr,TRUE,NETBIOS_NAME_SIZE,&pResp);
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // cache the name and contact the name
+ // server to get the name to IP mapping
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ status = RegOrQueryFromNet(
+ FALSE, //means it is a name query
+ pDeviceContext,
+ pNameHdr,
+ lNameSize,
+ pName,
+ pScope);
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ else
+ {
+ //
+ // the name is on the pending list doing a name query
+ // now, so ignore this name query request
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ }
+ }
+ else
+ {
+
+ //
+ // The name can be in the RESOLVED, RESOLVING or RELEASED
+ // state.
+ //
+
+
+ //
+ // If in the RELEASED state, its reference count has to be
+ // > 0
+ //
+ //ASSERT(pResp->NameTypeState & (STATE_RESOLVED | STATE_RESOLVING) || (pResp->NameTypeState & STATE_RELEASED) && (pResp->RefCount > 0));
+
+ //
+ // Send a response only if the name is in the RESOLVED state
+ //
+ if (pResp->NameTypeState & STATE_RESOLVED)
+ {
+
+ //
+ // The PROXY sends a response if the address of the
+ // node queries is not on the same subnet as the
+ // node doing the query (or as us). It also responds
+ // if the name is a group name or if it belongs to
+ // a Pnode. Note: In theory there is no reason to
+ // respond for group names since a member of the group
+ // on the subnet will respond with their address if they
+ // are alive - if they are B or M nodes - perhaps
+ // the fPnode bit is not set correctly for groups, so
+ // therefore always respond in case all the members
+ // are pnodes.
+ //
+
+ //
+ // If we have multiple network addresses in the same
+ // broadcast area, then this test won't be sufficient
+ //
+ if (
+ ((SrcAddress & pDeviceContext->SubnetMask)
+ !=
+ (pResp->IpAddress & pDeviceContext->SubnetMask))
+ ||
+ (pResp->fPnode)
+ ||
+ !(pResp->NameTypeState & NAMETYPE_UNIQUE)
+ )
+ {
+ IF_DBG(NBT_DEBUG_PROXY)
+ KdPrint(("QueryFromNet: QUERY SATISFIED by PROXY CACHE -- name is %16.16s(%X); %s entry ; Address is (%d)\n",
+ pResp->Name,pResp->Name[15], (pResp->NameTypeState & NAMETYPE_UNIQUE) ? "UNIQUE" : "INET_GROUP",
+ pResp->IpAddress));
+ //
+ //build a positive name query response pdu
+ //
+ // UdpSendQueryResponse frees the spin lock
+ //
+ status = UdpSendResponse(
+ lNameSize,
+ pNameHdr,
+ pResp,
+ (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
+ pDeviceContext,
+ 0,
+ eNAME_QUERY_RESPONSE,
+ OldIrq1);
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_PROXY)
+ KdPrint(("QueryFromNet: REQUEST for Name %16.16s(%X) in %s state\n", pResp->Name, pResp->Name[15],( pResp->NameTypeState & STATE_RELEASED ? "RELEASED" : "RESOLVING")));
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ }
+
+ } // end of proxy code
+#endif
+
+ } // end of else (it is a name query request)
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+RegResponseFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN USHORT OpCodeFlags
+ )
+/*++
+
+Routine Description:
+
+ This routine handles name registration responses from the net (i.e. from
+ the name server most of the time since a broadcast name registration passes
+ when there is no response.
+
+***
+ The response could be from an NBT node when it notices that the name
+ registration is for a name that it has already claimed - i.e. the node
+ is sending a NAME_CONFLICT_DEMAND - in this case the Rcode in the PDU
+ will be CFT_ERR = 7.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not - failure means no response to net
+
+--*/
+{
+ NTSTATUS status;
+ ULONG lNameSize;
+ CHAR pName[NETBIOS_NAME_SIZE];
+ PUCHAR pScope;
+ tNAMEADDR *pResp; //Get rid of this later. Use pNameAddr
+ tTIMERQENTRY *pTimer;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+ PTRANSPORT_ADDRESS pSourceAddress;
+ CTELockHandle OldIrq1;
+ ULONG SrcAddress;
+ SHORT SrcPort;
+
+
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
+ SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
+ SrcPort = ntohs(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->sin_port);
+ //
+ // be sure the Pdu is at least a minimum size
+ //
+ if (lNumBytes < (NBT_MINIMUM_REGRESPONSE + NbtConfig.ScopeLength -1))
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Registration Response TOO short = %X, Src = %X\n",
+ lNumBytes,SrcAddress));
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("%.*X\n",lNumBytes/sizeof(ULONG),pNameHdr));
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ //
+ // if Wins is locally attached then we will get registrations from
+ // ourselves!!
+ //
+ if (SrcIsUs(SrcAddress)
+#ifndef VXD
+ && !pWinsInfo
+#endif
+ )
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // get the name out of the network pdu and pass to routine to check
+ // local table *TODO* this assumes just one name in the Query response...
+ // We need to handle group lists from the WINS server
+ status = ConvertToAscii(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ lNumBytes,
+ pName,
+ &pScope,
+ &lNameSize);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ status = FindInHashTable(NbtConfig.pLocalHashTbl,
+ pName,
+ pScope,
+ &pResp);
+ if (NT_SUCCESS(status) &&
+ (pResp->AdapterMask & pDeviceContext->AdapterNumber))
+ {
+ NTSTATUS Localstatus;
+
+ //
+ // check the state of the name since this could be a registration
+ // response or a name conflict demand
+ //
+ switch (pResp->NameTypeState & NAME_STATE_MASK)
+ {
+
+ case STATE_RESOLVING:
+ case STATE_RESOLVED:
+
+ if (IS_POS_RESPONSE(OpCodeFlags))
+ {
+ if (OpCodeFlags & FL_RECURAVAIL)
+ {
+ // turn on the refreshed bit in NextRefresh now
+ // (when the timer completion routine is called)
+ // only count names registered, not REFRESHES too!
+ //
+ if (pResp->NameTypeState & STATE_RESOLVING)
+ {
+ IncrementNameStats(NAME_REGISTRATION_SUCCESS,
+ SrcIsNameServer(SrcAddress,SrcPort));
+ }
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ //
+ // in this case the name server is telling this node
+ // to do an end node challenge on the name. However
+ // this node does not have the code to do a challenge
+ // so assume that this is a positive registration
+ // response.
+ //
+ status = STATUS_SUCCESS;
+ }
+ }
+ else
+ if ((OpCodeFlags & FL_RCODE) >= FL_NAME_ACTIVE)
+ {
+ // if we are multihomed, then we only allow the name server
+ // to send Name Active errors, since in normal operation this node
+ // could generate two different IP address for the same name
+ // query and confuse another client node into sending a Name
+ // Conflict. So jump out if a name conflict has been received
+ // from another node.
+ //
+ if ((NbtConfig.MultiHomed) &&
+ ((OpCodeFlags & FL_RCODE) == FL_NAME_CONFLICT))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ break;
+ }
+ status = STATUS_DUPLICATE_NAME;
+
+
+ //
+ // if the name is resolved and we get a negative response
+ // then mark the name as in the conflict state so it can't
+ // be used for any new sessions and this node will no longer
+ // defend it.
+ //
+ if (pResp->NameTypeState & STATE_RESOLVED)
+ {
+ pResp->NameTypeState &= ~NAME_STATE_MASK;
+ pResp->NameTypeState |= STATE_CONFLICT;
+ NbtLogEvent(EVENT_NBT_DUPLICATE_NAME,SrcAddress);
+ }
+
+ }
+ else
+ {
+ //
+ // we got some kind of WINS server failure ret code
+ // so just ignore it and assume the name registration
+ // succeeded.
+ //
+ status = STATUS_SUCCESS;
+ }
+
+ // remove any timer block and call the completion routine
+ // if the name is in the Resolving state only
+ //
+ LOCATION(0x40);
+ if ((pTimer = pResp->pTimer))
+ {
+ tDGRAM_SEND_TRACKING *pTracker;
+ USHORT SendTransactId;
+ tDEVICECONTEXT *pDevContext;
+
+ // check the transaction id to be sure it is the same as the one
+ // sent.
+ //
+ LOCATION(0x41);
+ pTracker = (tDGRAM_SEND_TRACKING *)pTimer->Context;
+ SendTransactId = pTracker->TransactionId;
+ pDevContext = pTracker->pDeviceContext;
+
+ if (pNameHdr->TransactId != SendTransactId)
+ {
+ LOCATION(0x42);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ LOCATION(0x43);
+
+ CHECK_PTR(pResp);
+ pResp->pTimer = NULL;
+ //
+ // This could be either a Refresh or a name registration. In
+ // either case, stop the timer and call the completion routine
+ // for the client.(below).
+ //
+ Localstatus = StopTimer(pTimer,&pClientCompletion,&Context);
+
+
+ // check if it is a response from the name server
+ // and a M, or P or MS node, since we will need to send
+ // refreshes to the name server for these node types
+ //
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
+
+ // only accept pdus from the name server to change the Ttl.
+ // The first check passes the case where WINS is on this machine
+ //
+ if (
+#ifndef VXD
+ (pWinsInfo &&
+ (SrcAddress == pWinsInfo->pDeviceContext->IpAddress)) ||
+#endif
+ (SrcAddress == pDeviceContext->lNameServerAddress))
+ {
+ if (!(NodeType & BNODE) &&
+ (status == STATUS_SUCCESS) &&
+ (IS_POS_RESPONSE(OpCodeFlags)))
+ {
+ SetupRefreshTtl(pNameHdr,pResp,lNameSize);
+
+ // a name refresh response if in the resolved state
+ }
+ }
+ else
+ if ( SrcAddress == pDeviceContext->lBackupServer)
+ {
+ // switching the backup and the primary nameservers in
+ // the config data structure since we got a name
+ // registration response from the backup
+ //
+ SwitchToBackup(pDeviceContext);
+
+ if (!(NodeType & BNODE) &&
+ (status == STATUS_SUCCESS) &&
+ (IS_POS_RESPONSE(OpCodeFlags)))
+ {
+
+ SetupRefreshTtl(pNameHdr,pResp,lNameSize);
+
+ }
+
+ }
+ //
+ // mark name as refreshed if we got through to WINS Ok
+ //
+ if ((pClientCompletion) && (IS_POS_RESPONSE(OpCodeFlags)))
+ {
+ pResp->RefreshMask |= pDevContext->AdapterNumber;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // the completion routine has not run yet, so run it - this
+ // is the Registration Completion routine and we DO want it to
+ // run to mark the entry refreshed (NextRefresh)
+ if (pClientCompletion)
+ {
+ LOCATION(0x44);
+ (*pClientCompletion)(Context,status);
+ }
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ }
+
+ break;
+
+
+ default:
+ //
+ // if multiple (neg)registration responses are received, subsequent ones
+ // after the first will go through this path because the state of
+ // the name will have been changed by the first to CONFLICT
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+
+ }
+
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ } // end of else block (If name is not in local table)
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+CheckRegistrationFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes
+ )
+/*++
+
+Routine Description:
+
+ This routine handles name registrations from the network that are
+ potentially duplicates of names in the local name table. It compares
+ name registrations against its local table and defends any attempts to
+ take a name that is owned by this node. This routine handles name registration
+ REQUESTS.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not - failure means no response to net
+
+--*/
+{
+ NTSTATUS status;
+ ULONG lNameSize;
+ CHAR pName[NETBIOS_NAME_SIZE];
+ PUCHAR pScope;
+ tNAMEADDR *pResp;
+ tTIMERQENTRY *pTimer;
+ PTRANSPORT_ADDRESS pSourceAddress;
+ USHORT RegType;
+ CTELockHandle OldIrq1;
+ ULONG SrcAddress;
+
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
+ SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
+ //
+ // check the pdu size for errors
+ //
+ if (lNumBytes < (NBT_MINIMUM_REGREQUEST + NbtConfig.ScopeLength - 1))
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Registration Request TOO short = %X,Src = %X\n",
+ lNumBytes,SrcAddress));
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("%.*X\n",lNumBytes/sizeof(ULONG),pNameHdr));
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ //
+ // check if this message came from Us !! (and return if so)
+ //
+
+ if (SrcIsUs(SrcAddress))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // get the name out of the network pdu and pass to routine to check
+ // local table *TODO* this assumes just one name in the Query response...
+ status = ConvertToAscii(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ lNumBytes,
+ pName,
+ &pScope,
+ &lNameSize);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ status = FindInHashTable(NbtConfig.pLocalHashTbl,
+ pName,
+ pScope,
+ &pResp);
+
+
+ if (NT_SUCCESS(status))
+ {
+
+ RegType = GetNbFlags(pNameHdr,lNameSize);
+
+ // don't defend the broadcast name
+ if (pName[0] == '*')
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // we defend against anyone trying to take a unique name, or anyone
+ // trying to register a unique name for a group name we have. - if
+ // the name is registered on this adapter
+ //
+ if (((pResp->NameTypeState & NAMETYPE_UNIQUE) ||
+ ((pResp->NameTypeState & NAMETYPE_GROUP) &&
+ ((RegType & FL_GROUP) == 0))) &&
+ (pResp->AdapterMask & pDeviceContext->AdapterNumber))
+ {
+
+ //
+ // check the state of the name since this could be registration
+ // for the same name while we are registering the name. If another
+ // node claims the name at the same time, then cancel the name
+ // registration.
+ //
+ switch (pResp->NameTypeState & NAME_STATE_MASK)
+ {
+
+ case STATE_RESOLVING:
+
+ // remove any timer block and call the completion routine
+ if ((pTimer = pResp->pTimer))
+ {
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+
+ status = StopTimer(pTimer,&pClientCompletion,&Context);
+ CHECK_PTR(pResp);
+ pResp->pTimer = NULL;
+
+
+ if (pClientCompletion)
+ {
+
+ // LET THE COMPLETION ROUTINE CHANGE the state of the entry
+
+ status = STATUS_DUPLICATE_NAME;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // the completion routine has not run yet, so run it
+ (*pClientCompletion)(Context,status);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ }
+
+ }
+ break;
+
+ case STATE_RESOLVED:
+ //
+ // We must defend our name against this Rogue attempting to steal
+ // our Name! ( unless the name is "*")
+ //
+ status = UdpSendResponse(
+ lNameSize,
+ pNameHdr,
+ pResp,
+ (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
+ pDeviceContext,
+ REGISTRATION_ACTIVE_ERR,
+ eNAME_REGISTRATION_RESPONSE,
+ OldIrq1);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ break;
+
+ }
+
+
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ }
+ else
+ {
+ //
+ // NOTE: We have the Joint Lock
+ //
+
+ //
+ // The name is not in the local name table, so check if the proxy is
+ // on and if we want the proxy to check name registrations. The
+ // trouble with checking name registrations is that the proxy code
+ // only does a name query, so it will fail any node that is trying
+ // to change its address such as a RAS client coming in on a downlevel
+ // NT machine that only does broadcast name registrations. If
+ // that same user had previously dialled in on a WINS supporting RAS
+ // machine, their address would be in WINS, then dialling in on the
+ // downlevel machine would find that 'old' registration and deny
+ // the new one ( even though it is the same machine just changing
+ // its ip address).
+ //
+
+#ifdef PROXY_NODE
+
+ if ((NodeType & PROXY) &&
+ (NbtConfig.EnableProxyRegCheck))
+ {
+
+ BOOLEAN fResp = (BOOLEAN)FALSE;
+
+ //
+ // If name is RESOLVED in the remote table, has a different
+ // address than the node claiming the name, is not on the
+ // same subnet or is a Pnode then send a negative name
+ // registration response
+ //
+
+ //
+ // call this routine to find the name, since it does not
+ // interpret the state of the name as does FindName()
+ //
+ status = FindInHashTable(NbtConfig.pRemoteHashTbl,
+ pName,
+ pScope,
+ &pResp);
+
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // We need to send a query to WINS to
+ // see if the name is already taken or not.
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ status = RegOrQueryFromNet(
+ TRUE, //means it is a reg. from the net
+ pDeviceContext,
+ pNameHdr,
+ lNameSize,
+ pName,
+ pScope
+ );
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ //
+ // If the name is in the RESOLVED state, we need to determine
+ // whether we should respond or not. For a name that is not
+ // the RESOLVED state, the decision is simple. We don't respond
+ if (pResp->NameTypeState & STATE_RESOLVED)
+ {
+
+ ULONG IPAdd;
+
+ RegType = GetNbFlags(pNameHdr,lNameSize);
+ //
+ // If a unique name is being registered but our cache shows
+ // the name to be a group name (normal or internet), we
+ // send a negative name registration response.
+ //
+ // If a node on the same subnet has responded negatively also,
+ // it is ok. It is possible that WINS/NBNS has old
+ // information but there is no easy way to determine the
+ // network address of the node that registered the group.
+ // (For a normal group, there could have been several
+ // nodes that registered it -- their addresses are not stored
+ // by WINS.
+ //
+ if (!(RegType & FL_GROUP) &&
+ !(pResp->NameTypeState & NAMETYPE_UNIQUE))
+ {
+ fResp = TRUE;
+ }
+ else
+ {
+ tGENERALRR UNALIGNED *pResrcRecord;
+
+ // get the Ip address out of the Registration request
+ pResrcRecord = (tGENERALRR *)
+ ((ULONG)&pNameHdr->NameRR.NetBiosName[lNameSize]);
+
+ IPAdd = ntohl(pResrcRecord->IpAddress);
+ //
+ // If a group name is being registered but our cache shows
+ // the name to be a unique name (normal or internet) or
+ // if a UNIQUE name is being registered but clashes with
+ // a unique name with a different address, we check if the
+ // the addresses belong to the same subnet. If they do, we
+ // don't respond, else we send a negative registration
+ // response.
+ //
+ // Note: We never respond to a group registration
+ // that clashes with a group name in our cache.
+ //
+ if (((RegType & FL_GROUP)
+ &&
+ (pResp->NameTypeState & NAMETYPE_UNIQUE))
+ ||
+ (!(RegType & FL_GROUP)
+ &&
+ (pResp->NameTypeState & NAMETYPE_UNIQUE)
+ &&
+ IPAdd != pResp->IpAddress))
+ {
+ IF_DBG(NBT_DEBUG_PROXY)
+ KdPrint(("CheckReg:Subnet Mask = (%x)\nIPAdd=(%x)\npResp->IPAdd = (%x)\npResp->fPnode=(%d)\nIt is %s name %16.16s(%X)\nRegType Of Name Recd is %x\n---------------\n",
+ pDeviceContext->SubnetMask, IPAdd, pResp->IpAddress,
+ pResp->fPnode,
+ pResp->NameTypeState & NAMETYPE_GROUP ? "GROUP" : "UNIQUE",
+ pName, pName[15], RegType));
+ //
+ // Are the querying node and the queried node on the
+ // same subnet ?
+ //
+ if (((IPAdd & pDeviceContext->SubnetMask)
+ !=
+ (pResp->IpAddress & pDeviceContext->SubnetMask))
+ ||
+ (pResp->fPnode))
+ {
+ fResp = TRUE;
+ }
+ }
+ }
+
+ //
+ // If a negative response needs to be sent, send it now
+ //
+ if (fResp)
+ {
+
+ IF_DBG(NBT_DEBUG_PROXY)
+ KdPrint(("CheckRegistrationFromNet: Sending a negative name registration response for name %16.16s(%X) to node with address (%d)\n",
+ pResp->Name, pResp->Name[15], IPAdd));
+
+ //
+ // a different node is responding to the name query
+ // so tell them to buzz off.
+ //
+ status = UdpSendResponse(
+ lNameSize,
+ pNameHdr,
+ pResp,
+ (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
+ pDeviceContext,
+ REGISTRATION_ACTIVE_ERR,
+ eNAME_REGISTRATION_RESPONSE,
+ OldIrq1);
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ }
+ } // end of if (NAME is in the RESOLVED state)
+ }
+#endif
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ }
+ return(STATUS_DATA_NOT_ACCEPTED);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NameReleaseFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes
+ )
+/*++
+
+Routine Description:
+
+ This routine handles name releases that arrive from the Net. The idea
+ is to delete the name from the remote cache if it exists there so that
+ this node does not erroneously use that cached information anymore.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not - failure means no response to net
+
+--*/
+{
+ NTSTATUS status;
+ ULONG lNameSize;
+ CHAR pName[NETBIOS_NAME_SIZE];
+ PUCHAR pScope;
+ tNAMEADDR *pResp;
+ PTRANSPORT_ADDRESS pSourceAddress;
+ CTELockHandle OldIrq1;
+ USHORT OpCodeFlags;
+ tTIMERQENTRY *pTimer;
+ ULONG SrcAddress;
+ USHORT Flags;
+ USHORT SendTransactId;
+ tDGRAM_SEND_TRACKING *pTracker;
+ BOOLEAN bLocalTable;
+ tGENERALRR UNALIGNED *pRemainder;
+ USHORT SrcPort;
+ ULONG Rcode;
+
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
+ SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
+ SrcPort = ntohs(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->sin_port);
+ //
+ // check the pdu size for errors
+ //
+ if (lNumBytes < (NBT_MINIMUM_REGRESPONSE + NbtConfig.ScopeLength -1))
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Release Request/Response TOO short = %X, Src = %X\n",lNumBytes,
+ SrcAddress));
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("%.*X\n",lNumBytes/sizeof(ULONG),pNameHdr));
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ //
+ // check if this message came from Us !!
+ //
+ if (SrcIsUs(SrcAddress))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // get the name out of the network pdu and pass to routine to check
+ status = ConvertToAscii(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ lNumBytes,
+ pName,
+ &pScope,
+ &lNameSize);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ OpCodeFlags = pNameHdr->OpCodeFlags;
+
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
+ SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
+
+
+ //
+ // *** RESPONSE ***
+ //
+ if (OpCodeFlags & OP_RESPONSE)
+ {
+
+ //
+ // check the pdu size for errors
+ //
+ if (lNumBytes < (NBT_MINIMUM_REGRESPONSE + NbtConfig.ScopeLength -1))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ //
+ // call this routine to find the name, since it does not interpret the
+ // state of the name as does FindName()
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ status = FindInHashTable(NbtConfig.pLocalHashTbl,
+ pName,
+ pScope,
+ &pResp);
+ if (!NT_SUCCESS(status))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // Get the Timer block
+ if (!(pTimer = pResp->pTimer))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ //
+ // the name server is responding to a name release request
+ //
+ // check the transaction id to be sure it is the same as the one
+ // sent.
+ //
+ pTracker = (tDGRAM_SEND_TRACKING *)pTimer->Context;
+ SendTransactId = pTracker->TransactionId;
+ if (pNameHdr->TransactId != SendTransactId)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // for MS & M nodes if there is a response from the name server,
+ // then switch to broadcast name release.
+ //
+ //
+ switch (NodeType & NODE_MASK)
+ {
+
+ case MNODE:
+ case MSNODE:
+
+
+ if (SrcIsNameServer(SrcAddress,SrcPort))
+ {
+
+ Flags = pTracker->Flags;
+
+ if (Flags & NBT_NAME_SERVER)
+ {
+ //
+ // the next timeout will then switch to broadcast name
+ // release.
+ //
+ pTimer->Retries = 1;
+ }
+
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ case PNODE:
+ //
+ //
+ // this routine puts the timer block back on the timer Q, and
+ // handles race conditions to cancel the timer when the timer
+ // is expiring.
+ //
+ if ((pTimer = pResp->pTimer))
+ {
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+
+ status = StopTimer(pTimer,&pClientCompletion,&Context);
+
+ CHECK_PTR(pResp);
+ pResp->pTimer = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // the completion routine has not run yet, so run it
+ if (pClientCompletion)
+ {
+ (*pClientCompletion)(Context,STATUS_SUCCESS);
+ }
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ }
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ case BNODE:
+ default:
+ //
+ // normally there should be no response to a name release
+ // from a Bnode, but if there is, ignore it.
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ }
+
+ }
+ else
+ {
+ //
+ // It is a RELEASE REQUEST - so decide if the name should be removed
+ // from the remote or local table
+ //
+
+ // check the pdu size for errors
+ //
+ if (lNumBytes < (NBT_MINIMUM_REGREQUEST + NbtConfig.ScopeLength -1))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ // check the REMOTE hash table for the name...
+ //
+ status = FindInHashTable(NbtConfig.pRemoteHashTbl,
+ pName,
+ pScope,
+ &pResp);
+ bLocalTable = FALSE;
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // check the LOCAL name table for the name since the name server
+ // could be doing the equivalent of a name conflict demand
+ //
+ status = FindInHashTable(NbtConfig.pLocalHashTbl,
+ pName,
+ pScope,
+ &pResp);
+
+
+ bLocalTable = TRUE;
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ // check if the address being released corresponds to the one in
+ // the table - if not then ignore the release request - since someone
+ // else presumably tried to get the name, was refused and now is
+ // sending a name release request.
+ //
+ pRemainder = (tGENERALRR *)&pNameHdr->NameRR.NetBiosName[lNameSize];
+ if (pResp->IpAddress != (ULONG)ntohl(pRemainder->IpAddress))
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if (NT_SUCCESS(status))
+ {
+
+ //
+ // Don't remove group names, since a single group member
+ // releasing the name does not matter. Group names time
+ // out of the Remote table.
+ //
+ if (pResp->NameTypeState & NAMETYPE_UNIQUE)
+ {
+ switch (pResp->NameTypeState & NAME_STATE_MASK)
+ {
+
+ case STATE_RESOLVING:
+ //
+ // stop any timer that may be going
+ //
+ pTimer = pResp->pTimer;
+ CHECK_PTR(pResp);
+ pResp->pTimer = NULL;
+ //
+ // Local table means that it is a name registration
+ // and we must avoid calling CompleteClientReq
+ //
+ if (!bLocalTable)
+ {
+ StopTimerAndCallCompletion(pTimer,
+ STATUS_DUPLICATE_NAME,
+ OldIrq1);
+ }
+ else
+ {
+ if (pTimer)
+ {
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+
+ status = StopTimer(pTimer,&pClientCompletion,&Context);
+
+ // the completion routine has not run yet, so run it
+ if (pClientCompletion)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ (*pClientCompletion)(Context,STATUS_DUPLICATE_NAME);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ }
+ }
+ }
+
+ break;
+
+ case STATE_RESOLVED:
+ // dereference the name if it is in the remote table,
+ // this should change the state to RELEASED. For the
+ // local table just change the state to CONFLICT, since
+ // the local client still thinks it has the name open,
+ // however in the conflict state the name cannot be use
+ // to place new sessions and this node will not respond
+ // to name queries for the name.
+ //
+ if (!bLocalTable)
+ {
+ //
+ // if this is a pre-loaded name, just leave it alone
+ //
+ if (!(pResp->NameTypeState & PRELOADED))
+ {
+ //
+ // if someone is still using the name, do not
+ // dereference it, since that would leave the
+ // ref count at 1, and allow RemoteHashTimeout
+ // code to remove it before the client using
+ // the name is done with it. Once the client is
+ // done with it (i.e. a connect request), they
+ // will deref it , setting the ref count to 1 and
+ // it will be suitable for reuse.
+ //
+ if (pResp->RefCount > 1)
+ {
+ pResp->NameTypeState &= ~NAME_STATE_MASK;
+ pResp->NameTypeState |= STATE_CONFLICT;
+ }
+ else
+ {
+ NbtDereferenceName(pResp);
+ }
+ }
+ }
+ else
+ {
+ pResp->NameTypeState &= ~NAME_STATE_MASK;
+ pResp->NameTypeState |= STATE_CONFLICT;
+ NbtLogEvent(EVENT_NBT_NAME_RELEASE,SrcAddress);
+
+ }
+ break;
+
+ default:
+ break;
+
+ }
+ }
+
+
+ //
+ // tell WINS that the name released ok
+ //
+ Rcode = 0;
+ }
+ else
+ {
+ Rcode = NAME_ERROR;
+ }
+
+ //
+ // Only respond if not a broadcast...
+ //
+ if (!(OpCodeFlags & FL_BROADCAST))
+ {
+ status = UdpSendResponse(
+ lNameSize,
+ pNameHdr,
+ NULL,
+ (PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0],
+ pDeviceContext,
+ Rcode,
+ eNAME_RELEASE,
+ OldIrq1);
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ }
+
+ } // end of Release Request processing
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+WackFromNet(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes
+ )
+/*++
+
+Routine Description:
+
+ This routine handles Wait Acks from the name server. It finds the corresponding
+ name service transaction and changes the timeout of that transaction according
+ to the TTL field in the WACK.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not - failure means no response to net
+
+--*/
+{
+ NTSTATUS status;
+ ULONG lNameSize;
+ CHAR pName[NETBIOS_NAME_SIZE];
+ PUCHAR pScope;
+ tNAMEADDR *pNameAddr;
+ CTELockHandle OldIrq1;
+ ULONG Ttl;
+ tTIMERQENTRY *pTimerEntry;
+
+ //
+ // check the pdu size for errors
+ //
+ if (lNumBytes < (NBT_MINIMUM_WACK + NbtConfig.ScopeLength -1))
+ {
+ KdPrint(("Nbt:WACK TOO short = %X\n",lNumBytes));
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // get the name out of the network pdu and pass to routine to check
+ status = ConvertToAscii(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ lNumBytes,
+ pName,
+ &pScope,
+ &lNameSize);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+#ifdef VXD
+ if ( FindContextDirect( pNameHdr->TransactId ) != NULL )
+ {
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+#endif // VXD
+ status = FindInHashTable(NbtConfig.pLocalHashTbl,
+ pName,
+ pScope,
+ &pNameAddr);
+#ifdef VXD
+ }
+#endif // VXD
+
+ if (NT_SUCCESS(status))
+ {
+ Ttl = *(ULONG UNALIGNED *)( (ULONG)&pNameHdr->NameRR.NetBiosName[0]
+ + lNameSize
+ + FIELD_OFFSET(tQUERYRESP,Ttl) );
+ Ttl = ntohl(Ttl);
+
+ pTimerEntry = pNameAddr->pTimer;
+ if (pTimerEntry)
+ {
+
+ // convert seconds to milliseconds and put into the DeltaTime
+ // field so that when the next timeout occurs it changes the timer
+ // value to this new one. Depending on how many timeouts are left
+ // this could cause the client to wait several times the WACK timeout
+ // value. For example a Name query nominally has two retries, so if
+ // the WACK returns before the first retry then the total time waited
+ // will be 2*Ttl. This is not a problem since the real reason for
+ // the timeout is to prevent waiting forever for a dead name server.
+ // If the server returns a WACK it is not dead and the chances are
+ // that it will return a response before the timeout anyway.
+ //
+ // The timeout routine checks if TIMER_RETIMED is set and restarts
+ // the timeout without any processing if that is true ( and clears
+ // the flag too).
+ //
+ Ttl *= 1000;
+ if (Ttl > pTimerEntry->DeltaTime)
+ {
+ pTimerEntry->DeltaTime = Ttl;
+ pTimerEntry->Flags |= TIMER_RETIMED;
+ }
+
+ }
+
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SetupRefreshTtl(
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN tNAMEADDR *pNameAddr,
+ IN LONG lNameSize
+ )
+/*++
+
+Routine Description:
+
+ This routine handles name refresh timeouts. It looks at the Ttl in the
+ registration response and determines if the Node's refresh timeout should
+ be lengthened or shortened. To do this both the Ttl and the name associated
+ with the Ttl are kept in the Config structure. If the Ttl becomes longer
+ for the shortest names Ttl, then all the names use the longer value.
+
+Arguments:
+
+Return Value:
+
+ NTSTATUS - success or not - failure means no response to net
+
+--*/
+{
+ NTSTATUS status;
+ ULONG Ttl;
+ tTIMERQENTRY *pTimerQEntry;
+
+ // the Ttl in the pdu is in seconds. We need to convert it to milliseconds
+ // to use for our timer. This limits the timeout value to about 50 days
+ // ( 2**32 / 3600/24/1000 - milliseconds converted to days.)
+ //
+ Ttl = *(ULONG UNALIGNED *)(
+ (PUCHAR)&pNameHdr->NameRR.NetBiosName[0]
+ + lNameSize
+ + FIELD_OFFSET(tQUERYRESP,Ttl)
+ );
+
+ Ttl = ntohl(Ttl);
+
+ // the Ttl value may overflow the value we can store in Milliseconds,
+ // check for this case, and if it happens, use the longest timeout possible
+ // that still runs refresh, - i.e. NBT_MAXIMUM_TTL disables refresh
+ // altogether, so use NBT_MAXIMUM_TTL-1).
+ if (Ttl >= 0xFFFFFFFF/1000)
+ {
+ Ttl = NBT_MAXIMUM_TTL - 1;
+ }
+ else
+ {
+ Ttl *= 1000; // convert to milliseconds
+ }
+
+ // a zero Ttl means infinite, so set time the largest timeout
+ //
+ if (Ttl == 0)
+ {
+ Ttl = NBT_MAXIMUM_TTL; // set very large number which turns off refreshes
+ }
+ else
+ if (Ttl < NBT_MINIMUM_TTL)
+ {
+ Ttl = NBT_MINIMUM_TTL;
+ }
+
+ // Set the Ttl for the name record
+ //
+ pNameAddr->Ttl = Ttl;
+
+ //
+ // decide what to do about the existing timer....
+ // If the new timeout is shorter, then cancel the
+ // current timeout and start another one.
+ //
+ if (Ttl < NbtConfig.MinimumTtl)
+ {
+ KdPrint(("Nbt:Shortening Refresh Ttl from %d to %d\n",
+ NbtConfig.MinimumTtl, Ttl));
+
+ NbtConfig.MinimumTtl = (ULONG)Ttl;
+ pTimerQEntry = NbtConfig.pRefreshTimer;
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ //
+ // don't allow the stop timer routine to call the completion routine
+ // for the timer.
+ //
+ CHECK_PTR(pTimerQEntry);
+ if (pTimerQEntry)
+ {
+ pTimerQEntry->CompletionRoutine = NULL;
+ status = StopTimer(pTimerQEntry,NULL,NULL);
+ }
+
+ // keep the timeout for checking refreshes to about 10 minutes
+ // max. (MAX_REFRESH_CHECK_INTERVAL). If the refresh interval
+ // is less than 80 minutes then always use a refresh divisor of
+ // 8 - this allows the initial default ttl of 16 minutes to result
+ // in retries every 2 minutes.
+ //
+ NbtConfig.RefreshDivisor = NbtConfig.MinimumTtl/MAX_REFRESH_CHECK_INTERVAL;
+ if (NbtConfig.RefreshDivisor < REFRESH_DIVISOR)
+ {
+ NbtConfig.RefreshDivisor = REFRESH_DIVISOR;
+ }
+
+ //
+ // start the timer
+ //
+ status = StartTimer(
+ Ttl/NbtConfig.RefreshDivisor,
+ NULL, // context value
+ NULL, // context2 value
+ RefreshTimeout,
+ NULL,
+ NULL,
+ 0,
+ &NbtConfig.pRefreshTimer);
+#if DBG
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("Nbt:Failed to start a new timer for refresh\n"));
+ }
+#endif
+
+ }
+ else
+ if (Ttl > NbtConfig.MinimumTtl)
+ {
+ tHASHTABLE *pHashTable;
+ LONG i;
+ PLIST_ENTRY pHead,pEntry;
+
+ // PUT this code back in again, since it is possible that the name
+ // server could miss registering a name due to being busy and if we
+ // lengthen the timeout here then that name will not get into wins for
+ // a very long time.
+
+ // the shortest Ttl got longer, check if there is another shortest
+ // Ttl by scanning the local name table.
+ //
+ pHashTable = NbtConfig.pLocalHashTbl;
+ for (i=0;i < pHashTable->lNumBuckets ;i++ )
+ {
+ pHead = &pHashTable->Bucket[i];
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ //
+ // Find a valid name with a lower TTL if possible
+ //
+ if ((pNameAddr->Name[0] != '*') &&
+ ((pNameAddr->NameTypeState & STATE_RESOLVED)) &&
+ (pNameAddr->Ttl < (ULONG)Ttl) &&
+ (!(pNameAddr->NameTypeState & NAMETYPE_QUICK)))
+ {
+ if (pNameAddr->Ttl >= NBT_MINIMUM_TTL)
+ {
+ NbtConfig.MinimumTtl = pNameAddr->Ttl;
+ }
+ return;
+ }
+ pEntry = pEntry->Flink;
+ }
+ }
+
+ //
+ // if we get to here then there is no shorter ttl, so use the new
+ // ttl received from the WINS as the ttl. The next time the refresh
+ // timer expires it will restart with this new ttl
+ //
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Lengthening Refresh Ttl from %d to %d\n",
+ NbtConfig.MinimumTtl, Ttl));
+
+ NbtConfig.MinimumTtl = Ttl;
+
+ // keep the timeout for checking refreshes to about 10 minutes
+ // max. (MAX_REFRESH_CHECK_INTERVAL). If the refresh interval
+ // is less than 80 minutes then always use a refresh divisor of
+ // 8 - this allows the initial default ttl of 16 minutes to result
+ // in retries every 2 minutes.
+ //
+ NbtConfig.RefreshDivisor = NbtConfig.MinimumTtl/MAX_REFRESH_CHECK_INTERVAL;
+ if (NbtConfig.RefreshDivisor < REFRESH_DIVISOR)
+ {
+ NbtConfig.RefreshDivisor = REFRESH_DIVISOR;
+ }
+
+ }
+
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+DecodeNodeStatusResponse(
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN ULONG Length,
+ IN PUCHAR pName,
+ IN ULONG lNameSize,
+ IN ULONG SrcIpAddress
+ )
+/*++
+
+Routine Description:
+
+ This routine handles putting the node status response pdu into the clients
+ MDL.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ NTSTATUS status;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PLIST_ENTRY pNext;
+ tNODESTATUS UNALIGNED *pNodeStatus;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq2;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tTIMERQENTRY *pTimer;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID pClientContext;
+ BOOL MatchFound=FALSE;
+ ULONG IpAddress;
+
+
+ // first find the originating request in the NodeStatus list
+ CTESpinLock(&NbtConfig.JointLock,OldIrq2);
+ CTESpinLock(&NbtConfig,OldIrq);
+
+ pHead = &NbtConfig.NodeStatusHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pTracker = CONTAINING_RECORD(pEntry,tDGRAM_SEND_TRACKING,Linkage);
+
+ //
+ // find who sent the request originally
+ //
+ MatchFound = FALSE;
+ if (pTracker->Flags & REMOTE_ADAPTER_STAT_FLAG)
+ {
+ IpAddress = Nbt_inet_addr(pTracker->pNameAddr->Name);
+ }
+ else
+ {
+ IpAddress = 0;
+ }
+ if (
+ (CTEMemEqu(pName,pTracker->pNameAddr->Name,NETBIOS_NAME_SIZE))
+ || ((IpAddress==SrcIpAddress)&&(IpAddress!=0))
+ )
+ {
+ //
+ // if we directed node status request to an ipaddr without knowing
+ // its netbios name, then name is stored as "* ".
+ //
+ if ( (pName[0] == '*') && ( IpAddress == 0 ) )
+ {
+ int i=0;
+
+ //
+ // SrcIpAddress may not match the ipaddr to which we sent if
+ // remote host is multihomed: so search whole list of all
+ // ipaddrs for that host
+ //
+ ASSERT(pTracker->pNameAddr->pIpAddrsList);
+ while(pTracker->pNameAddr->pIpAddrsList[i])
+ {
+ if (pTracker->pNameAddr->pIpAddrsList[i++] == SrcIpAddress)
+ {
+ MatchFound = TRUE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ MatchFound = TRUE;
+ }
+ }
+ else
+ {
+ MatchFound = FALSE;
+ }
+
+ if (MatchFound)
+ {
+ RemoveEntryList(pEntry);
+
+ pNodeStatus = (tNODESTATUS *)&pNameHdr->NameRR.NetBiosName[lNameSize];
+
+ // this is the amount of data left, that we do not want to go
+ // beyond, otherwise the system will bugcheck
+ //
+ Length -= FIELD_OFFSET(tNAMEHDR,NameRR.NetBiosName) + lNameSize;
+
+ pTimer = pTracker->Connect.pTimer;
+ if (pTimer)
+ {
+ CTESpinFree(&NbtConfig,OldIrq);
+
+ status = StopTimer(pTimer,&pClientCompletion,&pClientContext);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+
+ if (pClientCompletion)
+ {
+ //
+ // if there is a ClientContext then this node status qry was
+ // started because of a session setup attempt: extract the
+ // server name out of the node status response and continue
+ // with the session setup phase
+ //
+ if (pClientContext)
+ {
+ status = ExtractServerName(pNodeStatus,
+ pClientContext,
+ SrcIpAddress);
+
+ DereferenceTracker(pTracker);
+
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ status);
+ // (*pClientCompletion)(pClientContext,status);
+ }
+ //
+ // there is no ClientContext which means this node status query
+ // was started because of a remote adapter status request
+ // (e.g. nbtstat -a): extract all names out of the node status
+ // response and complete the remote adapter status irp
+ //
+ else
+ {
+ PVOID pBuffer;
+
+ // bump this up to non dispatch level processing
+ pBuffer = NbtAllocMem(Length,NBT_TAG('7'));
+ if (pBuffer)
+ {
+ CTEMemCopy(pBuffer,(PVOID)pNodeStatus,Length);
+ pTracker->SrcIpAddress = SrcIpAddress;
+ pTracker->pNodeStatus = pBuffer;
+ pTracker->NodeStatusLen = Length;
+
+ CTEQueueForNonDispProcessing(pTracker,
+ pTracker,
+ pClientCompletion,
+ CopyNodeStatusResponse,
+ NULL);
+ }
+ }
+ }
+
+ break;
+ } else {
+ //
+ // Free the lock nonetheless.
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+
+ ASSERTMSG("Nbt:found node status element, but Timer is NULL!\n",0);
+ }
+ }
+ else
+ {
+ pEntry = pEntry->Flink;
+ }
+
+ }
+
+ if (!MatchFound)
+ {
+ CTESpinFree(&NbtConfig,OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+ }
+
+ return(STATUS_UNSUCCESSFUL);
+}
+
+typedef enum _dest_type {
+ IP_ADDR,
+ DNS,
+ NETBIOS
+} DEST_TYPE;
+
+//----------------------------------------------------------------------------
+ DEST_TYPE
+GetDestType(
+ IN PUCHAR pName
+ )
+
+/*++
+Routine Description:
+
+ Classifies name passed in as an IP addr/Netbios name/Dns name
+
+Arguments:
+
+Return Value:
+ DEST_TYPE
+
+--*/
+{
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("GetDestType: input: %s\n", pName));
+
+ if (Nbt_inet_addr(pName)) {
+ return IP_ADDR;
+ } else {
+ if ((pName[NETBIOS_NAME_SIZE-1] <= 0x20 ) ||
+ (pName[NETBIOS_NAME_SIZE-1] >= 0x7f )) {
+ return NETBIOS;
+ } else {
+ //
+ // else 16 byte DNS name
+ //
+ return DNS;
+ }
+
+ }
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+ExtractServerName(
+ IN tNODESTATUS UNALIGNED *pNodeStatus,
+ IN PVOID pClientContext,
+ IN ULONG IpAddress
+ )
+
+/*++
+Routine Description:
+
+ This Routine searches for the server name (name ending with 0x20) from the
+ list of names returned by node status response, and adds that name to the
+ remote hash table.
+
+Arguments:
+
+ pNodeStatus Node status response from the remote host
+ pClientContext Tracker for the seutp phase
+ IpAddress Ip address of the node that just responded
+
+Return Value:
+
+ NTSTATUS - status of the request
+ Success, if we find the server name
+ Bad_Network_Path if we couldn't find the server name
+
+--*/
+
+{
+
+ NTSTATUS status;
+ NTSTATUS Locstatus;
+ ULONG i;
+ UCHAR Flags;
+ PCHAR pName;
+ tNAMEADDR *pNameAddr;
+ tDGRAM_SEND_TRACKING *pClientTracker;
+ tSESSIONREQ *pSessionReq;
+ PUCHAR pCopyTo;
+ CTELockHandle OldIrq;
+ DEST_TYPE DestType;
+
+
+
+ status = STATUS_BAD_NETWORK_PATH;
+
+ pClientTracker = (tDGRAM_SEND_TRACKING *)pClientContext;
+
+ if (pClientTracker->SendBuffer.Length > NETBIOS_NAME_SIZE) {
+ DestType = DNS;
+ } else {
+ DestType = GetDestType(pClientTracker->pDestName);
+ }
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("ExtractSrvName: DestType: %d\n", DestType));
+
+ for(i =0; i<pNodeStatus->NumNames; i++)
+ {
+ pName = &pNodeStatus->NodeName[i].Name[0];
+
+ //
+ // For IP addresses and DNS names, we map the 0x20 name to the corresp 0x0 name
+ // for datagram sends.
+ //
+ if ((DestType == IP_ADDR) || (DestType == DNS)) {
+ if (pName[NETBIOS_NAME_SIZE-1] != 0x20)
+ continue;
+
+ // else
+ if (pClientTracker->Flags & DGRAM_SEND_FLAG) {
+ pName[NETBIOS_NAME_SIZE-1] = 0x0;
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("ExtractServerName: Mapping 0x20 name to 0x0\n"));
+ }
+
+ } else {
+ //
+ // For Netbios names (resolved via DNS), we match the 16th byte exactly
+ //
+ if (pName[NETBIOS_NAME_SIZE-1] != pClientTracker->pDestName[NETBIOS_NAME_SIZE-1])
+ continue;
+ }
+
+ Flags = pNodeStatus->NodeName[i].Flags;
+
+ //
+ // make sure it's a unique name (for connects only, for dgram sends, group names are fine)
+ // and is not in conflict or released
+ //
+ if ( (((pClientTracker->Flags & SESSION_SETUP_FLAG) && !(Flags & GROUP_STATUS)) ||
+ (pClientTracker->Flags & DGRAM_SEND_FLAG)) &&
+ !(Flags & NODE_NAME_CONFLICT) &&
+ !(Flags & NODE_NAME_RELEASED) )
+ {
+
+ //
+ // fix up the connection tracker to point to the right name, now
+ // that we know the server name to connect to
+ //
+
+ //
+ // The FIND_NAME_FLAG was set to indicate that this is not a session setup attempt so
+ // we can avoid the call to ConvertToHalfAscii.
+ //
+ if (!(pClientTracker->Flags & FIND_NAME_FLAG)) {
+
+ if ( pClientTracker->Flags & SESSION_SETUP_FLAG )
+ {
+ CTEMemCopy(pClientTracker->SendBuffer.pBuffer,pName,NETBIOS_NAME_SIZE);
+ CTEMemCopy(pClientTracker->Connect.pConnEle->RemoteName,
+ pName,
+ NETBIOS_NAME_SIZE);
+ #ifdef VXD
+ CTEMemCopy(&pClientTracker->pClientIrp->ncb_callname[0],pName,NETBIOS_NAME_SIZE);
+ #endif // VXD
+ pSessionReq = pClientTracker->SendBuffer.pDgramHdr;
+
+ //
+ // overwrite the Dest HalfAscii name in the Session Pdu with the correct name
+ //
+ pCopyTo = ConvertToHalfAscii( (PCHAR)&pSessionReq->CalledName.NameLength,
+ pName,
+ NbtConfig.pScope,
+ NbtConfig.ScopeLength);
+
+ } else if (pClientTracker->Flags & DGRAM_SEND_FLAG) {
+ PCHAR pCopyTo;
+ tDGRAMHDR *pDgramHdr;
+
+ //
+ // Overwrite the dest name, so SendDgramContinue can find the name
+ // in the caches.
+ //
+ CTEMemCopy(pClientTracker->pDestName,pName,NETBIOS_NAME_SIZE);
+
+ //
+ // Copy over the actual dest name in half-ascii
+ // This is immediately after the SourceName; so offset the
+ // dest by the length of the src name.
+ //
+ pDgramHdr = pClientTracker->SendBuffer.pDgramHdr;
+
+ pCopyTo = (PVOID)&pDgramHdr->SrcName.NameLength;
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("pCopyTo:%lx\n", pCopyTo));
+
+ pCopyTo += 1 + // Length field
+ 2 * NETBIOS_NAME_SIZE + // actual name in half-ascii
+ NbtConfig.ScopeLength; // length of scope
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("pCopyTo:%lx\n", pCopyTo));
+
+ ConvertToHalfAscii( pCopyTo,
+ pName,
+ NbtConfig.pScope,
+ NbtConfig.ScopeLength);
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("Copied the remote name for dgram sends\n"));
+ }
+
+ } else {
+ KdPrint(("ExtractServerName: Find name going on\n"));
+ }
+
+ //
+ // add this server name to the remote hashtable
+ //
+ pNameAddr = NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('8'));
+ if (!pNameAddr)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ CTEZeroMemory(pNameAddr,sizeof(tNAMEADDR));
+ InitializeListHead(&pNameAddr->Linkage);
+ CTEMemCopy(pNameAddr->Name,pName,NETBIOS_NAME_SIZE);
+ pNameAddr->Verify = REMOTE_NAME;
+ pNameAddr->RefCount = 1;
+ pNameAddr->NameTypeState = STATE_RESOLVED | NAMETYPE_UNIQUE;
+ pNameAddr->AdapterMask = (CTEULONGLONG)-1;
+ pNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
+ pNameAddr->IpAddress = IpAddress;
+
+ Locstatus = AddRecordToHashTable(pNameAddr,NbtConfig.pScope);
+
+ status = STATUS_SUCCESS;
+
+ //KdPrint(("Nbt NodeStat: Found SrvName. IpAddr = %x, Name = %16.16s<%X>\n",IpAddress,pName,pName[15]));
+
+ //
+ // if Nameaddr couldn't be added, it means an entry already exists
+ // Get that entry and update its ipaddr.
+ //
+ if (!NT_SUCCESS(Locstatus))
+ {
+ //KdPrint(("Nbt ExtractSrv: couldn't add nameaddr for %16.16s<%X>\n",pName,pName[15]));
+ NbtDereferenceName(pNameAddr);
+ Locstatus = FindInHashTable( NbtConfig.pRemoteHashTbl,
+ pName,
+ NbtConfig.pScope,
+ &pNameAddr);
+ if (!NT_SUCCESS(Locstatus))
+ {
+ Locstatus = FindInHashTable( NbtConfig.pLocalHashTbl,
+ pName,
+ NbtConfig.pScope,
+ &pNameAddr);
+ }
+
+ if (NT_SUCCESS(Locstatus))
+ {
+ pNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
+ pNameAddr->IpAddress = IpAddress;
+ }
+ else
+ {
+ ASSERTMSG("Nbt ExtractSrv: couldn't find name in remote or loc table!\n",0);
+ status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ }
+
+ break; // found the name: done with the for loop
+ }
+ }
+
+ return( status );
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+CopyNodeStatusResponse(
+ IN PVOID pContext
+ )
+
+// IN tNODESTATUS UNALIGNED *pNodeStat,
+// IN ULONG TotalLength,
+// IN ULONG SrcIpAddress,
+// IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine copies data received from the net node status response to
+ the client's irp. It is called from inbound.c when a node status response
+ comes in from the wire.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG NumNames;
+ ULONG i;
+ PADAPTER_STATUS pAdapterStatus;
+ PNAME_BUFFER pNameBuffer;
+ ULONG BuffSize;
+ BOOLEAN Failed;
+ ULONG AccumLength;
+ PUCHAR pAscii;
+ UCHAR Flags;
+ ULONG DataLength;
+ ULONG DestSize ;
+ tSTATISTICS UNALIGNED *pStatistics;
+ ULONG SrcIpAddress;
+ ULONG TotalLength;
+ tNODESTATUS *pNodeStat;
+ tDGRAM_SEND_TRACKING *pTracker;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+ PIRP pIrp;
+
+ CTEPagedCode();
+
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)pContext)->pTracker;
+
+ SrcIpAddress = pTracker->SrcIpAddress;
+ TotalLength = pTracker->NodeStatusLen;
+ CHECK_PTR(pTracker);
+ pTracker->NodeStatusLen = 0;
+ pNodeStat = (tNODESTATUS *)pTracker->pNodeStatus;
+ pIrp = pTracker->pClientIrp;
+
+ NumNames = pNodeStat->NumNames;
+
+ BuffSize = sizeof(ADAPTER_STATUS) + NumNames*sizeof(NAME_BUFFER);
+
+ // sanity check that we are not allocating more than 64K for this stuff
+ if (BuffSize > 0xFFFF)
+ {
+ status = STATUS_UNSUCCESSFUL;
+ goto ExitRoutine;
+ }
+
+ pAdapterStatus = NbtAllocMem((USHORT)BuffSize,NBT_TAG('9'));
+ if (!pAdapterStatus)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ExitRoutine;
+ }
+
+ // Fill out the adapter status structure with zeros first
+ CTEZeroMemory((PVOID)pAdapterStatus,BuffSize);
+
+ // get the source MAC address from the statistics portion of the pdu
+ //
+ if (TotalLength >= (NumNames*sizeof(tNODENAME) + sizeof(tSTATISTICS)))
+ {
+ pStatistics = (tSTATISTICS UNALIGNED *)((PUCHAR)&pNodeStat->NodeName[0] + NumNames*sizeof(tNODENAME));
+
+ CTEMemCopy(&pAdapterStatus->adapter_address[0],
+ &pStatistics->UnitId[0],
+ sizeof(tMAC_ADDRESS));
+ }
+
+ pAdapterStatus->rev_major = 0x03;
+ pAdapterStatus->adapter_type = 0xFE; // pretend it is an ethernet adapter
+
+ //
+ // get the ptr to the statistics field if there is one in the pdu
+ //
+ AccumLength = NumNames * sizeof(tNODENAME) +
+ FIELD_OFFSET(tNODESTATUS, NodeName) + sizeof(USHORT) +
+ FIELD_OFFSET( tSTATISTICS, SessionDataPacketSize ) ;
+
+ if (AccumLength <= TotalLength)
+ {
+ //
+ // there is a whole statistics portion to the adapter status command,
+ // so we can get the session pdu size out of it.
+ //
+ pAdapterStatus->max_sess = ntohs((USHORT)*((PUCHAR)pNodeStat
+ + AccumLength
+ - sizeof(USHORT)));
+
+ }
+
+ // get the address of the name buffer at the end of the adapter status
+ // structure so we can copy the names into this area.
+ pNameBuffer = (PNAME_BUFFER)((ULONG)pAdapterStatus + sizeof(ADAPTER_STATUS));
+
+ // set the AccumLength to the start of the node name array in the buffer
+ // so we can count through the buffer and be sure not to run off the end
+ //
+ AccumLength = FIELD_OFFSET(tNODESTATUS, NodeName);
+
+ Failed = FALSE;
+ for(i =0; i< NumNames; i++)
+ {
+ AccumLength += sizeof(tNODENAME);
+ if (AccumLength > TotalLength)
+ {
+ Failed = TRUE;
+ break;
+ }
+ pAdapterStatus->name_count++ ;
+ pAscii = (PCHAR)&pNodeStat->NodeName[i].Name[0];
+ Flags = pNodeStat->NodeName[i].Flags;
+
+ pNameBuffer->name_flags = (Flags & GROUP_STATUS) ?
+ GROUP_NAME : UNIQUE_NAME;
+
+ //
+ // map the name states
+ //
+
+ if (Flags & NODE_NAME_CONFLICT)
+ {
+ if (Flags & NODE_NAME_RELEASED)
+ pNameBuffer->name_flags |= DUPLICATE_DEREG;
+ else
+ pNameBuffer->name_flags |= DUPLICATE;
+
+ }
+ else
+ if (Flags & NODE_NAME_RELEASED)
+ {
+ pNameBuffer->name_flags |= DEREGISTERED;
+ }
+ else
+ {
+ pNameBuffer->name_flags |= REGISTERED;
+ }
+
+ pNameBuffer->name_num = (UCHAR)i+1;
+
+ CTEMemCopy(pNameBuffer->name,pAscii,NETBIOS_NAME_SIZE);
+
+ pNameBuffer++;
+
+ }
+
+ //
+ // The remote buffer is incomplete, what else can we do?
+ //
+ if ( Failed )
+ {
+ status = STATUS_UNSUCCESSFUL;
+ goto ExitCleanup;
+ }
+
+
+ //
+ // Reduce the name count if we can't fit the buffer
+ //
+#ifdef VXD
+ DestSize = ((NCB*)pIrp)->ncb_length ;
+#else
+ DestSize = MmGetMdlByteCount( pIrp->MdlAddress ) ;
+#endif
+
+ CHECK_PTR(pAdapterStatus);
+ if ( BuffSize > DestSize )
+ {
+ if ( DestSize < sizeof( ADAPTER_STATUS ))
+ pAdapterStatus->name_count = 0 ;
+ else
+ pAdapterStatus->name_count = (WORD)
+ ( DestSize- sizeof(ADAPTER_STATUS)) / sizeof(NAME_BUFFER) ;
+
+ }
+
+ //
+ // Copy the built adapter status structure
+ //
+#ifdef VXD
+ if ( BuffSize > DestSize )
+ {
+ status = STATUS_BUFFER_OVERFLOW ;
+ BuffSize = DestSize ;
+ }
+ else
+ status = STATUS_SUCCESS ;
+
+ CTEMemCopy( ((NCB*)pIrp)->ncb_buffer,
+ pAdapterStatus,
+ BuffSize ) ;
+ //
+ // Set here to be compatible with NT
+ //
+ ((NCB*)pIrp)->ncb_length = (WORD) BuffSize ;
+
+#else
+ status = TdiCopyBufferToMdl (
+ pAdapterStatus,
+ 0,
+ BuffSize,
+ pIrp->MdlAddress,
+ 0,
+ &DataLength);
+
+ pIrp->IoStatus.Information = DataLength;
+
+ pIrp->IoStatus.Status = status;
+
+#endif
+
+ExitCleanup:
+ CTEMemFree((PVOID)pAdapterStatus);
+
+ExitRoutine:
+ Context = ((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
+ pClientCompletion = (COMPLETIONCLIENT)((NBT_WORK_ITEM_CONTEXT *)pContext)->ClientCompletion;
+
+ CTEMemFree(pNodeStat);
+ CTEMemFree(pContext);
+
+
+ // call the completion routine of the original node status request in
+ // name.c
+ (*pClientCompletion)(Context,status);
+
+ return;
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+SendNodeStatusResponse(
+ IN tNAMEHDR UNALIGNED *pInNameHdr,
+ IN ULONG Length,
+ IN PUCHAR pName,
+ IN ULONG lNameSize,
+ IN ULONG SrcIpAddress,
+ IN USHORT SrcPort,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles putting the node status response pdu into the clients
+ MDL.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ NTSTATUS status;
+ PUCHAR pScope;
+ PUCHAR pInScope;
+ ULONG Position;
+ ULONG CountNames;
+ ULONG BuffSize;
+ tNODESTATUS UNALIGNED *pNodeStatus;
+ tNAMEHDR *pNameHdr;
+ CTELockHandle OldIrq2;
+ ULONG i;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tADDRESSELE *pAddressEle;
+ tNAMEADDR *pNameAddr;
+ tDGRAM_SEND_TRACKING *pTracker;
+ ULONG InScopeLength;
+ tSTATISTICS UNALIGNED *pStatistics;
+ tNODENAME UNALIGNED *pNode;
+ CTEULONGLONG AdapterNumber;
+ ULONG Len;
+
+ if (Length > sizeof(tNAMEHDR) + lNameSize - 1 + sizeof(ULONG))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq2);
+
+ // verify that the requesting node is in the same scope as this node, so
+ // get a ptr to the scope, which starts 16*2 (32) bytes into the
+ // netbios name in the pdu.
+ //
+ pInScope = (PUCHAR)&pInNameHdr->NameRR.NetBiosName[(NETBIOS_NAME_SIZE <<1)];
+ pScope = NbtConfig.pScope;
+
+ Position = sizeof(tNAMEHDR) - sizeof(tNETBIOS_NAME) +1 + (NETBIOS_NAME_SIZE <<1);
+
+ // check the scope length
+ InScopeLength = Length - Position - sizeof(ULONG);
+ if (InScopeLength != NbtConfig.ScopeLength)
+ {
+ status = STATUS_DATA_NOT_ACCEPTED;
+ goto ErrorExit;
+ }
+
+ // compare scopes for equality and avoid running off the end of the pdu
+ //
+ i= 0;
+ while (i < NbtConfig.ScopeLength)
+ {
+ if (*pInScope != *pScope)
+ {
+ status = STATUS_DATA_NOT_ACCEPTED;
+ goto ErrorExit;
+ }
+ i++;
+ pInScope++;
+ pScope++;
+ }
+
+ // get the count of names, excluding '*...' which we do not send...
+ //
+ CountNames = CountLocalNames(&NbtConfig);
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Node Status Response, with %d names\n",CountNames));
+
+ // this is only a byte field, so only allow up to 255 names.
+ if (CountNames > 255)
+ {
+ CountNames = 255;
+ }
+
+
+ // Allocate Memory for the adapter status
+
+ // - ULONG for the Nbstat and IN that are part of Length. CountNames-1
+ // because there is one name in sizeof(tNODESTATUS) already
+ //
+ BuffSize = Length + sizeof(tNODESTATUS) - sizeof(ULONG) + (CountNames-1)*sizeof(tNODENAME)
+ + sizeof(tSTATISTICS);
+
+ pNameHdr = (tNAMEHDR *)NbtAllocMem((USHORT)BuffSize,NBT_TAG('A'));
+ if (!pNameHdr)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // copy the request to the response and change a few bits around
+ //
+ CHECK_PTR(pNameHdr);
+ CTEMemCopy((PVOID)pNameHdr,(PVOID)pInNameHdr,Length);
+ pNameHdr->OpCodeFlags = OP_RESPONSE | FL_AUTHORITY;
+ pNameHdr->QdCount = 0;
+ pNameHdr->AnCount = 1;
+
+ pNodeStatus = (tNODESTATUS UNALIGNED *)&pNameHdr->NameRR.NetBiosName[lNameSize];
+
+ CHECK_PTR(pNodeStatus);
+ pNodeStatus->Ttl = 0;
+
+
+ pNode = (tNODENAME UNALIGNED *)&pNodeStatus->NodeName[0];
+ AdapterNumber = pDeviceContext->AdapterNumber;
+
+ i = 0;
+ pEntry = pHead = &NbtConfig.AddressHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
+
+ pNameAddr = pAddressEle->pNameAddr;
+
+ pNode->Flags = (pAddressEle->NameType == NBT_UNIQUE) ?
+ UNIQUE_STATUS : GROUP_STATUS;
+
+ // all names have this one set
+ //
+ pNode->Flags |= NODE_NAME_ACTIVE;
+ switch (pNameAddr->NameTypeState & NAME_STATE_MASK)
+ {
+ default:
+ case STATE_RESOLVED:
+ break;
+
+ case STATE_CONFLICT:
+ pNode->Flags |= NODE_NAME_CONFLICT;
+ break;
+
+ case STATE_RELEASED:
+ pNode->Flags |= NODE_NAME_RELEASED;
+ break;
+
+ case STATE_RESOLVING:
+ // don't count these names.
+ continue;
+
+ }
+
+ switch (NodeType & NODE_MASK)
+ {
+ case BNODE:
+ pNode->Flags |= STATUS_BNODE;
+ break;
+
+ case MSNODE:
+ case MNODE:
+ pNode->Flags |= STATUS_MNODE;
+ break;
+
+ case PNODE:
+ pNode->Flags |= STATUS_PNODE;
+ }
+
+ CHECK_PTR(pNode);
+ pNode->Resrved = 0;
+
+ // Copy the name in the pdu
+ CTEMemCopy((PVOID)&pNode->Name[0],
+ (PVOID)pNameAddr->Name,
+ NETBIOS_NAME_SIZE);
+
+
+ // check for the permanent name...and add it too
+ //
+ if (pNameAddr->NameTypeState & NAMETYPE_QUICK)
+ {
+ // the permanent name is added as a Quick Add in the name
+ // table
+ //
+ // do not put the permanent name into the response
+ continue;
+
+ }
+ else
+ if ((pNameAddr->Name[0] == '*') ||
+ (pNameAddr->NameTypeState & STATE_RESOLVING) ||
+ (!(pNameAddr->AdapterMask & AdapterNumber)))
+ {
+ //
+ // do not put the broadcast name into the response, since neither
+ // NBF or WFW NBT puts it there.
+
+ // Also, to not respond with resolving names, or names that are
+ // not registered on this adapter (multihomed case)
+ //
+ continue;
+ }
+
+ i++;
+ pNode++;
+ }
+
+ //
+ // set the count of names in the response packet
+ //
+ pNodeStatus->NumNames = (UCHAR)i;
+
+ Len = i*sizeof(tNODENAME) + 1 + sizeof(tSTATISTICS); //+1 for NumNames Byte
+ pNodeStatus->Length = (USHORT)htons(Len);
+
+ // fill in some of the statistics fields which occur after the name table
+ // in the PDU
+ //
+ pStatistics = (tSTATISTICS UNALIGNED *)((PUCHAR)&pNodeStatus->NodeName[0]
+ + i*sizeof(tNODENAME));
+
+ CTEZeroMemory((PVOID)pStatistics,sizeof(tSTATISTICS));
+
+ //
+ // put the MAC address in the response
+ //
+ CTEMemCopy(&pStatistics->UnitId[0],
+ &pDeviceContext->MacAddress.Address[0],
+ sizeof(tMAC_ADDRESS));
+ //
+ // Now send the node status message
+ //
+ status = GetTracker(&pTracker);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+
+ if (!NT_SUCCESS(status))
+ {
+ CTEMemFree((PVOID)pNameHdr);
+
+ }
+ else
+ {
+ CHECK_PTR(pTracker);
+ pTracker->SendBuffer.HdrLength = BuffSize;
+ pTracker->SendBuffer.pDgramHdr = (PVOID)pNameHdr;
+ pTracker->SendBuffer.pBuffer = NULL;
+ pTracker->SendBuffer.Length = 0;
+
+ status = UdpSendDatagram(pTracker,
+ SrcIpAddress,
+ pDeviceContext->pNameServerFileObject,
+ QueryRespDone, // this routine frees memory and puts the tracker back
+ pTracker,
+ SrcPort, // NBT_NAMESERVICE_UDP_PORT 31343 - reply to port request came on....
+ NBT_NAME_SERVICE);
+ }
+
+ return(status);
+
+ErrorExit:
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+UpdateNameState(
+ IN tADDSTRUCT UNALIGNED *pAddrStruct,
+ IN tNAMEADDR *pNameAddr,
+ IN ULONG Len,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN BOOLEAN NameServerIsSrc,
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN CTELockHandle OldIrq1
+ )
+/*++
+
+Routine Description:
+
+ This routine handles putting a list of names into the hash table when
+ a response is received that contains one or more than one ip address.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+
+ LONG CountAddrs;
+ LONG i;
+ tIPLIST *pIpList;
+ ULONG ExtraNames;
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+
+ // a pos. response to a previous query, so change the state in the
+ // hash table to RESOLVED
+ if (pNameAddr->NameTypeState & STATE_RESOLVING)
+ {
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= STATE_RESOLVED;
+
+ // check if a group name...
+ //
+ if (ntohs(pAddrStruct->NbFlags) & FL_GROUP)
+ {
+ pNameAddr->NameTypeState &= ~NAME_TYPE_MASK;
+
+ // it is difficult to differentiate nameserver responses from
+ // single node responses, when a single ip address is returned.
+ // It could be the name server returning an Inet Group with one
+ // entry or another node simply responding with its address. The
+ // only way to check is to know if the source was a nameserver.
+ //
+ if ((Len == sizeof(tADDSTRUCT)) &&
+ (!NameServerIsSrc ||
+ (NameServerIsSrc && (pAddrStruct->IpAddr == (ULONG)-1))))
+ {
+
+ // using zero here tells the UdpSendDatagramCode to
+ // send to the subnet broadcast address when talking to
+ // that address.
+ CHECK_PTR(pNameAddr);
+ //
+ // For Bnodes store the Address of the node that responded
+ // to the group name query, since we do allow sessions to
+ // group names for BNODES since they can resolve the name to
+ // and IP address, whereas other nodes cannot.
+ //
+// store the ipaddr regardless of nodetype. We don't know if this info will be
+// used to setup a session or send a datagram. We do check NameTypeState
+// while setting up session, so no need to filter out NodeType info here.
+
+ //
+ // WINS puts -1 to say it's a groupname
+ //
+ if ( pAddrStruct->IpAddr == (ULONG)-1 )
+ pNameAddr->IpAddress = 0;
+ else
+ pNameAddr->IpAddress = ntohl(pAddrStruct->IpAddr);
+
+ pNameAddr->NameTypeState |= NAMETYPE_GROUP;
+ }
+ else
+ {
+ //
+ // one or more addresses were returned, so put them into a list
+ // that is pointed to by the pNameAddr record
+ //
+ CountAddrs = Len / sizeof(tADDSTRUCT);
+
+ if (CountAddrs > NBT_MAX_INTERNET_GROUP_ADDRS)
+ {
+ // probably a badly formated packet because the max number
+ // is 1000
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ ExtraNames = 2;
+ //
+ // allocate memory for the Internet Group address (+1 because
+ // there is a null ptr on the end of the list, +1 more for the
+ // broadcast address, and maybe +1 more for the local node)
+ //
+ pIpList = NbtAllocMem((USHORT)((CountAddrs+ExtraNames)*sizeof(tIPLIST)),NBT_TAG('B'));
+ if ( !pIpList )
+ return STATUS_INSUFFICIENT_RESOURCES ;
+
+ //
+ // put the broadcast address first
+ //
+ pIpList->IpAddr[0] = 0;
+
+ // extract the ipaddress from each address structure
+ for ( i = 1 ; i < CountAddrs+1; i++ )
+ {
+
+ pIpList->IpAddr[i] = ntohl(pAddrStruct->IpAddr);
+ pAddrStruct++;
+
+ }
+
+ // mark the end of the list
+ CHECK_PTR(pIpList);
+ pIpList->IpAddr[CountAddrs+1] = (ULONG)-1;
+
+ pNameAddr->pIpList = pIpList;
+ pNameAddr->NameTypeState |= NAMETYPE_INET_GROUP;
+ }
+ }
+ else
+ {
+ if (Len > sizeof(tADDSTRUCT))
+ {
+ ULONG IpAddress;
+ NBT_WORK_ITEM_CONTEXT *pContext;
+
+ // the name query response contains several ip addresses for
+ // a multihomed host, so pick an address that matches one of
+ // our subnet masks
+ //
+ // Do the old thing for datagram sends/name queries.
+ //
+ if ((NbtConfig.TryAllAddr) &&
+ (pTracker->Flags & SESSION_SETUP_FLAG)) {
+
+ // IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Kicking off CheckAddr : %lx\n", pAddrStruct));
+
+ ChooseBestIpAddress(pAddrStruct,Len,pDeviceContext, pTracker, &IpAddress, TRUE);
+
+ //
+ // At this point, pTracker->IPList contains the sorted list of destination
+ // IP addresses. Submit this list to the lmhsvc service to ping each and
+ // return whic is reachable.
+ //
+ pContext = (NBT_WORK_ITEM_CONTEXT *)NbtAllocMem(sizeof(NBT_WORK_ITEM_CONTEXT),NBT_TAG('H'));
+ if (!pContext)
+ {
+ KdPrint(("Nbt: NbtConnect: couldn't alloc mem for pContext\n"));
+ return(STATUS_SUCCESS);
+ }
+
+ pContext->pTracker = NULL; // no query tracker
+ pContext->pClientContext = pTracker; // the client tracker
+ pContext->ClientCompletion = SessionSetupContinue;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ status = DoCheckAddr(pContext);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("Nbt: DoCheckAddr returned %lx\n", status));
+ }
+
+ return (status); // shd be STATUS_PENDING
+ } else {
+
+ // IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Choosing best IP addr...\n"));
+
+ ChooseBestIpAddress(pAddrStruct,Len,pDeviceContext, pTracker, &IpAddress, FALSE);
+ pNameAddr->IpAddress = IpAddress;
+ }
+ }
+ else
+ {
+ // it is already set to a unique address...since that is the default
+ // when the name is queried originally.
+
+ pNameAddr->IpAddress = ntohl(pAddrStruct->IpAddr);
+ }
+
+ }
+ }
+
+ status = AddRecordToHashTable(pNameAddr,NbtConfig.pScope);
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // the name must already be in the hash table, so dereference it to
+ // remove it
+ //
+ NbtDereferenceName(pNameAddr);
+ }
+
+ return(STATUS_SUCCESS);
+}
+//----------------------------------------------------------------------------
+ ULONG
+MakeList(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN ULONG CountAddrs,
+ IN tADDSTRUCT UNALIGNED *pAddrStruct,
+ IN PULONG AddrArray,
+ IN ULONG SizeOfAddrArray,
+ IN BOOLEAN IsSubnetMatch
+ )
+/*++
+
+Routine Description:
+
+ This routine gets a list of ip addresses that match the network number
+ This can either be the subnet number or the network number depending
+ on the boolean IsSubnetMatch
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tDEVICECONTEXT *pTmpDevContext;
+ ULONG MatchAddrs = 0;
+ tADDSTRUCT UNALIGNED *pAddrs;
+ ULONG i;
+ ULONG IpAddr;
+ ULONG NetworkNumber;
+ ULONG NetworkNumberInIpAddr;
+ UCHAR IpAddrByte;
+
+ pHead = &NbtConfig.DeviceContexts;
+ pEntry = pHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pAddrs = pAddrStruct;
+
+ pTmpDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+ //
+ // DeviceContext is non-null, if a check has to be made on a specific
+ // DeviceContext. Otherwise it's null (i.e. check all DeviceContexts)
+ //
+ if (pDeviceContext)
+ {
+ if (pTmpDevContext != pDeviceContext)
+ continue;
+ }
+ if (IsSubnetMatch)
+ {
+ NetworkNumber = pTmpDevContext->SubnetMask & pTmpDevContext->IpAddress;
+ }
+ else
+ {
+ NetworkNumber = pTmpDevContext->NetMask;
+ }
+
+ // extract the ipaddress from each address structure
+ for ( i = 0 ; i < CountAddrs; i++ )
+ {
+
+ NetworkNumberInIpAddr = IpAddr = ntohl(pAddrs->IpAddr);
+
+ if (IsSubnetMatch)
+ {
+ if (((pTmpDevContext->SubnetMask & IpAddr) == NetworkNumber) &&
+ (MatchAddrs < SizeOfAddrArray/sizeof(ULONG)))
+ {
+ // put the ipaddress into a list incase multiple match
+ // and we want to select one randomly
+ //
+ AddrArray[MatchAddrs++] = IpAddr;
+
+ }
+ pAddrs++;
+ }
+ else
+ {
+ IpAddrByte = ((PUCHAR)&IpAddr)[3];
+ if ((IpAddrByte & 0x80) == 0)
+ {
+ // class A address - one byte netid
+ NetworkNumberInIpAddr &= 0xFF000000;
+ }
+ else
+ if ((IpAddrByte & 0xC0) ==0x80)
+ {
+ // class B address - two byte netid
+ NetworkNumberInIpAddr &= 0xFFFF0000;
+ }
+ else
+ if ((IpAddrByte & 0xE0) ==0xC0)
+ {
+ // class C address - three byte netid
+ NetworkNumberInIpAddr &= 0xFFFFFF00;
+ }
+ if ((NetworkNumberInIpAddr == NetworkNumber) &&
+ (MatchAddrs < SizeOfAddrArray/sizeof(ULONG)))
+ {
+ // put the ipaddress into a list incase multiple match
+ // and we want to select one randomly
+ //
+ AddrArray[MatchAddrs++] = IpAddr;
+
+ }
+ pAddrs++;
+ }
+ }
+ }
+
+ return(MatchAddrs);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+ChooseBestIpAddress(
+ IN tADDSTRUCT UNALIGNED *pAddrStruct,
+ IN ULONG Len,
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT tDGRAM_SEND_TRACKING *pTracker,
+ OUT PULONG pIpAddress,
+ IN BOOLEAN fTryAllAddr
+ )
+/*++
+
+Routine Description:
+
+ This routine gets a list of ip addresses and attempts to pick one of them
+ as the best address. This occurs when WINS returns a list of addresses
+ for a multihomed host and we want want the one that is on a subnet
+ corresponding to one of the network cards. Failing to match on
+ subnet mask, results in a random selection from the addresses.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+
+ ULONG CountAddrs;
+ CTESystemTime TimeValue;
+ ULONG Random;
+ ULONG AddrArray[60];
+ ULONG MatchAddrs = 0;
+
+ // one or more addresses were returned,
+ // so pick one that is best
+ //
+ CountAddrs = Len / sizeof(tADDSTRUCT);
+
+ if (CountAddrs*sizeof(tADDSTRUCT) == Len)
+ {
+
+ //
+ // First check if any addresses are on the same subnet as this
+ // devicecontext.
+ //
+ MatchAddrs = MakeList(
+ pDeviceContext,
+ CountAddrs,
+ pAddrStruct,
+ AddrArray,
+ sizeof(AddrArray),
+ TRUE);
+
+ //
+ // if none of the ipaddrs is on the same subnet as this DeviceContext,
+ // try other DeviceContexts
+ //
+ if (!MatchAddrs)
+ {
+ MatchAddrs = MakeList(
+ NULL,
+ CountAddrs,
+ pAddrStruct,
+ AddrArray,
+ sizeof(AddrArray),
+ TRUE);
+ }
+
+ //
+ // if none of the addresses match the subnet address of any of the
+ // DeviceContexts, then go through the same check looking for matches
+ // that have the same network number.
+ //
+ if (!MatchAddrs)
+ {
+ MatchAddrs = MakeList(
+ NULL,
+ CountAddrs,
+ pAddrStruct,
+ AddrArray,
+ sizeof(AddrArray),
+ FALSE);
+ }
+ }
+ else
+ {
+ // the pdu length is not an even multiple of the tADDSTRUCT data
+ // structure
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ // calls the kernel routine to get the system time.
+ //
+ CTEQuerySystemTime(TimeValue);
+
+
+ if (MatchAddrs)
+ {
+ if (!fTryAllAddr) {
+
+ Random = RandomizeFromTime( TimeValue, MatchAddrs ) ;
+ *pIpAddress = AddrArray[Random];
+ } else {
+ ULONG i,j;
+ tADDSTRUCT temp;
+
+ //
+ // Sort the IP addr list on basis of best IP addr. in AddrArray
+ //
+ // NOTE: this is not a strictly sorted list (the actual sort might be too expensive),
+ // instead we take all the addresses that match the subnet mask (say) and
+ // clump the remaining ones in the same group. This way we ensure that whatever
+ // we chose as the best address is still given preference as compared to the
+ // other addresses.
+ //
+ for (i=0; i<MatchAddrs; i++ ) {
+
+ //
+ // SWAP(pAddrStruct[i], pAddrStruct[Index(AddrArray[i])]);
+ //
+
+ //
+ // Index(AddrArray[i]) is final j
+ //
+ for (j=0; j<CountAddrs; j++) {
+ // IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:pAddrStruct[%d] : %lx AddrArray[%d]: %lx\n", j, pAddrStruct[j].IpAddr, i, AddrArray[i]));
+ if (pAddrStruct[j].IpAddr == (ULONG)ntohl(AddrArray[i])) {
+ break;
+ }
+ }
+
+ ASSERT(j < CountAddrs);
+
+ temp = pAddrStruct[i];
+ pAddrStruct[i] = pAddrStruct[j];
+ pAddrStruct[j] = temp;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Submit the list to lmhsvc as it is...
+ //
+
+ if (!fTryAllAddr) {
+ Random = RandomizeFromTime( TimeValue, CountAddrs ) ;
+
+ //
+ // if we get to here then the returned list of ip addresses does not
+ // match the network number of any of our adapters, so therefore just
+ // pick one randomly from the original list
+ //
+ *pIpAddress = htonl(pAddrStruct[Random].IpAddr);
+ }
+ }
+
+ if (fTryAllAddr) {
+ ULONG j;
+
+ pTracker->IpList = NbtAllocMem(sizeof(ULONG)*CountAddrs,NBT_TAG('8'));
+
+ if (pTracker->IpList) {
+ for (j=0; j<CountAddrs; j++) {
+ // IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:pAddrStruct[%d]: %lx\n", j, pAddrStruct[j].IpAddr));
+ pTracker->IpList[j] = pAddrStruct[j].IpAddr;
+ }
+ pTracker->IpList[j] = 0;
+ pTracker->NumAddrs = CountAddrs;
+ } else {
+ return (STATUS_INSUFFICIENT_RESOURCES);
+ }
+ }
+
+}
+//----------------------------------------------------------------------------
+ BOOLEAN
+SrcIsNameServer(
+ IN ULONG SrcAddress,
+ IN USHORT SrcPort
+ )
+/*++
+
+Routine Description:
+
+ This function checks the src address against all adapters' name server
+ address to see if it came from a name server.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or STATUS_UNSUCCESSFUL
+
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tDEVICECONTEXT *pDevContext;
+
+ pHead = &NbtConfig.DeviceContexts;
+ pEntry = pHead->Flink;
+
+ if (SrcPort == NbtConfig.NameServerPort)
+ {
+ while (pEntry != pHead)
+ {
+ pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+
+ if ((pDevContext->lNameServerAddress == SrcAddress) ||
+ (pDevContext->lBackupServer == SrcAddress))
+ {
+ return(TRUE);
+ }
+ pEntry = pEntry->Flink;
+ }
+ }
+#ifndef VXD
+ //
+ // If wins is on this machine the above SrcIsNameServer
+ // check may not be sufficient since this machine is
+ // the name server and that check checks the nameservers
+ // used for name queries. If WINS is on this machine it will send
+ // from the first adapter's ip address.
+ //
+ if (pWinsInfo &&
+ (pWinsInfo->pDeviceContext->IpAddress == SrcAddress))
+ {
+ return(TRUE);
+ }
+
+#endif
+ return(FALSE);
+
+}
+
+
+//----------------------------------------------------------------------------
+ BOOLEAN
+SrcIsUs(
+ IN ULONG SrcAddress
+ )
+/*++
+
+Routine Description:
+
+ This function checks the src address against all adapters'Ip addresses
+ address to see if it came from this node.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or STATUS_UNSUCCESSFUL
+
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tDEVICECONTEXT *pDevContext;
+
+ pHead = &NbtConfig.DeviceContexts;
+ pEntry = pHead->Flink;
+
+ while (pEntry != pHead)
+ {
+ pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+
+ if (pDevContext->IpAddress == SrcAddress)
+ {
+ return(TRUE);
+ }
+ pEntry = pEntry->Flink;
+ }
+
+ return(FALSE);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+SwitchToBackup(
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This function switches the primary and backup name server addresses.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or STATUS_UNSUCCESSFUL
+
+
+--*/
+{
+ ULONG SaveAddr;
+
+ SaveAddr = pDeviceContext->lNameServerAddress;
+
+ //
+ // Bug: 30511: Dont switch servers if no backup.
+ //
+ if (pDeviceContext->lBackupServer == LOOP_BACK) {
+ IF_DBG(NBT_DEBUG_REFRESH)
+ KdPrint(("Nbt:Will not Switch to backup name server: devctx: %X, refreshtobackup=%X\n",
+ pDeviceContext, pDeviceContext->RefreshToBackup));
+ return;
+ }
+
+ pDeviceContext->lNameServerAddress = pDeviceContext->lBackupServer;
+ pDeviceContext->lBackupServer = SaveAddr;
+
+ IF_DBG(NBT_DEBUG_REFRESH)
+ KdPrint(("Nbt:Switching to backup name server: devctx: %X, refreshtobackup=%X\n",
+ pDeviceContext, pDeviceContext->RefreshToBackup));
+
+ // keep track if we are on the backup or not.
+ pDeviceContext->RefreshToBackup = ~pDeviceContext->RefreshToBackup;
+
+}
+
+//----------------------------------------------------------------------------
+ USHORT
+GetNbFlags(
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN ULONG lNameSize
+ )
+/*++
+
+Routine Description:
+
+ This function finds the Nbflags field in certain pdu types and returns it.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or STATUS_REMOTE_NOT_LISTENING
+
+Called By: RegResponseFromNet
+
+--*/
+{
+ USHORT RegType;
+ ULONG QuestionNameLen;
+
+ //
+ // if the question name is not a pointer to the first name then we
+ // must find the end of that name and adjust it so when added to
+ // to lNameSize we endup at NB_FLAGS
+ //
+ if (( pNameHdr->NameRR.NetBiosName[lNameSize+PTR_OFFSET] & PTR_SIGNATURE)
+ != PTR_SIGNATURE)
+ {
+ // add one to include the null on the end of the string + the NB, IN TTL,
+ // and length fields( another 10 bytes NO_PTR_OFFSET) + PTR_OFFSET(4).
+ //
+ QuestionNameLen =
+ strlen((PUCHAR)&pNameHdr->NameRR.NetBiosName[lNameSize+PTR_OFFSET])
+ +1 + NO_PTR_OFFSET + PTR_OFFSET;
+ }
+ else
+ {
+ QuestionNameLen = NBFLAGS_OFFSET;
+ }
+
+ RegType = ntohs((USHORT)pNameHdr->NameRR.NetBiosName[lNameSize
+ +QuestionNameLen ]);
+ return(RegType);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+FindOnPendingList(
+ IN PUCHAR pName,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN BOOLEAN DontCheckTransactionId,
+ IN ULONG BytesToCompare,
+ OUT tNAMEADDR **ppNameAddr
+
+ )
+/*++
+
+Routine Description:
+
+ This function is called to look for a name query request on the pending
+ list. It searches the list linearly to look for the name.
+
+ The Joint Lock is held when calling this routine.
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tNAMEADDR *pNameAddr;
+ tTIMERQENTRY *pTimer;
+
+ pHead = pEntry = &NbtConfig.PendingNameQueries;
+
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+
+ //
+ // there could be multiple entries with the same name so check the
+ // transaction id too
+ //
+ if (DontCheckTransactionId ||
+ ((pTimer = pNameAddr->pTimer) &&
+ (((tDGRAM_SEND_TRACKING *)pTimer->Context)->TransactionId == pNameHdr->TransactId))
+ &&
+ (CTEMemEqu(pNameAddr->Name,pName,BytesToCompare)))
+ {
+ *ppNameAddr = pNameAddr;
+ return(STATUS_SUCCESS);
+ }
+ }
+
+
+ return(STATUS_UNSUCCESSFUL);
+}
+
+
+
+#if DBG
+//----------------------------------------------------------------------------
+ VOID
+PrintHexString(
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN ULONG lNumBytes
+ )
+/*++
+
+Routine Description:
+
+ This function is called to determine whether the name packet we heard on
+ the net has the same address as the one in the remote hash table.
+ If it has the same address or if it does not have any address, we return
+ SUCCESS, else we return NOT_LISTENING.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or STATUS_REMOTE_NOT_LISTENING
+
+Called By: RegResponseFromNet
+
+--*/
+{
+ ULONG i,Count=0;
+ PUCHAR pHdr=(PUCHAR)pNameHdr;
+
+ for (i=0;i<lNumBytes ;i++ )
+ {
+ KdPrint(("%2.2X ",*pHdr));
+ pHdr++;
+ if (Count >= 16)
+ {
+ Count = 0;
+ KdPrint(("\n"));
+ }
+ else
+ Count++;
+ }
+ KdPrint(("\n"));
+}
+#endif
+
+#ifdef PROXY_NODE
+//----------------------------------------------------------------------------
+ NTSTATUS
+ChkIfValidRsp(
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNameSize,
+ IN tNAMEADDR *pNameAddr
+ )
+/*++
+
+Routine Description:
+
+ This function is called to determine whether the name packet we heard on
+ the net has the same address as the one in the remote hash table.
+ If it has the same address or if it does not have any address, we return
+ SUCCESS, else we return NOT_LISTENING.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or STATUS_REMOTE_NOT_LISTENING
+
+Called By: RegResponseFromNet
+
+--*/
+{
+ ULONG IpAdd;
+
+ IpAdd = ntohl(
+ pNameHdr->NameRR.NetBiosName[lNameSize+IPADDRESS_OFFSET]
+ );
+
+ //
+ // If the IP address in the packet received is same as the one
+ // in the table we return success, else we are not interested
+ // in the packet (we want to just drop the packet)
+ //
+ if (
+ (IpAdd == pNameAddr->IpAddress)
+ )
+ {
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ return(STATUS_REMOTE_NOT_LISTENING);
+ }
+}
+#endif
+
+
diff --git a/private/ntos/nbt/nbt/init.c b/private/ntos/nbt/nbt/init.c
new file mode 100644
index 000000000..e69827f8b
--- /dev/null
+++ b/private/ntos/nbt/nbt/init.c
@@ -0,0 +1,1037 @@
+/**********************************************************************/
+/** Microsoft Windows/NT **/
+/** Copyright(c) Microsoft Corp., 1992 **/
+/**********************************************************************/
+
+/*
+ Init.c
+
+ OS Independent initialization routines
+
+
+
+ FILE HISTORY:
+ Johnl 26-Mar-1993 Created
+*/
+
+
+#include "nbtnt.h"
+#include "nbtprocs.h"
+
+VOID
+ReadScope(
+ IN tNBTCONFIG *pConfig,
+ IN HANDLE ParmHandle
+ );
+
+VOID
+ReadLmHostFile(
+ IN tNBTCONFIG *pConfig,
+ IN HANDLE ParmHandle
+ );
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(INIT, InitNotOs)
+#ifdef _PNP_POWER
+#pragma CTEMakePageable(PAGE, InitTimersNotOs)
+#pragma CTEMakePageable(PAGE, StopInitTimers)
+#else // _PNP_POWER
+#pragma CTEMakePageable(INIT, InitTimersNotOs)
+#pragma CTEMakePageable(INIT, StopInitTimers)
+#endif // _PNP_POWER
+#pragma CTEMakePageable(PAGE, ReadParameters)
+#pragma CTEMakePageable(PAGE, ReadParameters2)
+#pragma CTEMakePageable(PAGE, ReadScope)
+#pragma CTEMakePageable(PAGE, ReadLmHostFile)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+#ifdef VXD
+#pragma BEGIN_INIT
+#endif
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+InitNotOs(
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ This is the initialization routine for the Non-OS Specific side of the
+ NBT device driver.
+
+ pNbtGlobConfig must be initialized before this is called!
+
+Arguments:
+
+Return Value:
+
+ NTSTATUS - The function value is the final status from the initialization
+ operation.
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG i;
+
+
+ CTEPagedCode();
+ //
+ // for multihomed hosts, this tracks the number of adapters as each one
+ // is created.
+ //
+ NbtConfig.AdapterCount = 0;
+ NbtConfig.MultiHomed = FALSE;
+ NbtConfig.SingleResponse = FALSE;
+
+
+ //
+ // Initialize the name statistics
+ //
+ CTEZeroMemory( &NameStatsInfo,sizeof(tNAMESTATS_INFO) );
+
+ InitializeListHead(&pNbtGlobConfig->DeviceContexts);
+
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ InitializeListHead(&pNbtGlobConfig->FreeDevCtx);
+#endif
+
+ InitializeListHead(&NbtConfig.AddressHead);
+ InitializeListHead(&NbtConfig.PendingNameQueries);
+
+#ifdef VXD
+ InitializeListHead(&NbtConfig.DNSDirectNameQueries);
+#endif
+
+ // initialize the spin lock
+ CTEInitLock(&pNbtGlobConfig->SpinLock);
+ CTEInitLock(&pNbtGlobConfig->JointLock.SpinLock);
+ NbtConfig.LockNumber = NBTCONFIG_LOCK;
+ NbtConfig.JointLock.LockNumber = JOINT_LOCK;
+ NbtMemoryAllocated = 0;
+
+#if DBG
+ for (i=0;i<MAXIMUM_PROCESSORS ;i++ )
+ {
+ NbtConfig.CurrentLockNumber[i] = 0;
+ }
+#endif
+ InitializeListHead(&UsedTrackers);
+ InitializeListHead(&UsedIrps);
+
+ // create the hash tables for storing names in.
+ status = CreateHashTable(&pNbtGlobConfig->pLocalHashTbl,
+ pNbtGlobConfig->uNumBucketsLocal,
+ NBT_LOCAL);
+
+ if ( !NT_SUCCESS( status ) )
+ {
+ ASSERTMSG("NBT:Unable to create hash tables for Netbios Names\n",
+ (status == STATUS_SUCCESS));
+ return status ;
+ }
+ // we always have a remote hash table, but if we are a Proxy, it is
+ // a larger table. In the Non-proxy case the remote table just caches
+ // names resolved with the NS. In the Proxy case it also holds names
+ // resolved for all other clients on the local broadcast area.
+ // The node size registry parameter controls the number of remote buckets.
+ status = InitRemoteHashTable(pNbtGlobConfig,
+ pNbtGlobConfig->uNumBucketsRemote,
+ pNbtGlobConfig->uNumRemoteNames);
+
+ if ( !NT_SUCCESS( status ) )
+ return status ;
+
+ //
+ // initialize the linked lists associated with the global configuration
+ // data structures
+ //
+ InitializeListHead(&NbtConfig.NodeStatusHead);
+ InitializeListHead(&NbtConfig.DgramTrackerFreeQ);
+#ifndef VXD
+ InitializeListHead(&NbtConfig.IrpFreeList);
+ pWinsInfo = 0;
+
+ {
+
+ //
+ // Setup the default disconnect timeout - 10 seconds - convert
+ // to negative 100 Ns.
+ //
+ DefaultDisconnectTimeout.QuadPart = Int32x32To64(DEFAULT_DISC_TIMEOUT,
+ MILLISEC_TO_100NS);
+ DefaultDisconnectTimeout.QuadPart = -(DefaultDisconnectTimeout.QuadPart);
+ }
+
+#else
+ DefaultDisconnectTimeout = DEFAULT_DISC_TIMEOUT * 1000; // convert to milliseconds
+
+ InitializeListHead(&NbtConfig.SendTimeoutHead) ;
+ InitializeListHead(&NbtConfig.SessionBufferFreeList) ;
+ InitializeListHead(&NbtConfig.SendContextFreeList) ;
+ InitializeListHead(&NbtConfig.RcvContextFreeList) ;
+
+ //
+ // For session headers, since they are only four bytes and we can't
+ // change the size of the structure, we'll covertly add enough for
+ // a full LIST_ENTRY and treat it like a standalone LIST_ENTRY structure
+ // when adding and removing from the list.
+ //
+ NbtConfig.iBufferSize[eNBT_SESSION_HDR] = sizeof(tSESSIONHDR) +
+ sizeof( LIST_ENTRY ) - sizeof(tSESSIONHDR) ;
+ NbtConfig.iBufferSize[eNBT_SEND_CONTEXT] = sizeof(TDI_SEND_CONTEXT);
+ NbtConfig.iBufferSize[eNBT_RCV_CONTEXT] = sizeof(RCV_CONTEXT);
+
+ NbtConfig.iCurrentNumBuff[eNBT_SESSION_HDR] = NBT_INITIAL_NUM;
+ status = NbtInitQ( &NbtConfig.SessionBufferFreeList,
+ NbtConfig.iBufferSize[eNBT_SESSION_HDR],
+ NBT_INITIAL_NUM);
+
+ if ( !NT_SUCCESS( status ) )
+ return status ;
+
+ NbtConfig.iCurrentNumBuff[eNBT_SEND_CONTEXT] = NBT_INITIAL_NUM;
+ status = NbtInitQ( &NbtConfig.SendContextFreeList,
+ sizeof( TDI_SEND_CONTEXT ),
+ NBT_INITIAL_NUM);
+
+ if ( !NT_SUCCESS( status ) )
+ return status ;
+
+ NbtConfig.iCurrentNumBuff[eNBT_RCV_CONTEXT] = NBT_INITIAL_NUM;
+ status = NbtInitQ( &NbtConfig.RcvContextFreeList,
+ sizeof( RCV_CONTEXT ),
+ NBT_INITIAL_NUM);
+
+ if ( !NT_SUCCESS( status ) )
+ return status ;
+#endif
+
+ //
+ // create trackers List
+ //
+ pNbtGlobConfig->iBufferSize[eNBT_DGRAM_TRACKER] =
+ sizeof(tDGRAM_SEND_TRACKING);
+
+ NbtConfig.iCurrentNumBuff[eNBT_DGRAM_TRACKER] = 0;
+
+ status = NbtInitTrackerQ( &NbtConfig.DgramTrackerFreeQ,NBT_INITIAL_NUM);
+
+ if ( !NT_SUCCESS( status ) )
+ return status ;
+
+
+ CTEZeroMemory(&LmHostQueries,sizeof(tLMHOST_QUERIES));
+ InitializeListHead(&DomainNames.DomainList);
+ InitializeListHead(&LmHostQueries.ToResolve);
+
+#ifndef VXD
+ // set up a list for connections when we run out of resources and need to
+ // disconnect these connections. An Irp is also needed for this list, and
+ // it is allocated in Driver.C after we have created the connections to the
+ // transport and therefore know our Irp Stack Size.
+ //
+ InitializeListHead(&NbtConfig.OutOfRsrc.ConnectionHead);
+
+ // use this resources to synchronize access to the security info between
+ // assigning security and checking it - when adding names to the
+ // name local name table through NbtregisterName. This also insures
+ // that the name is in the local hash table (from a previous Registration)
+ // before the next registration is allowed to proceed and check for
+ // the name in the table.
+ //
+ ExInitializeResource(&NbtConfig.Resource);
+
+ //
+ // this resource is used to synchronize access to the Dns structure
+ //
+ CTEZeroMemory(&DnsQueries,sizeof(tDNS_QUERIES));
+
+ InitializeListHead(&DnsQueries.ToResolve);
+
+ //
+ // this resource is used to synchronize access to the Dns structure
+ //
+ CTEZeroMemory(&CheckAddr,sizeof(tCHECK_ADDR));
+
+ InitializeListHead(&CheckAddr.ToResolve);
+#endif // VXD
+
+ return status ;
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+InitTimersNotOs(
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ This is the initialization routine for the Non-OS Specific side of the
+ NBT device driver that starts the timers needed.
+
+Arguments:
+
+Return Value:
+
+ NTSTATUS - The function value is the final status from the initialization
+ operation.
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ tTIMERQENTRY *pTimerEntry;
+
+ CTEPagedCode();
+ // create the timer control blocks, setting the number of concurrent timers
+ // allowed at one time
+ status = InitTimerQ(NBT_INITIAL_NUM);
+ NbtConfig.iBufferSize[eNBT_TIMER_ENTRY] = sizeof(tTIMERQENTRY);
+ NbtConfig.iCurrentNumBuff[eNBT_TIMER_ENTRY] = NBT_INITIAL_NUM;
+
+
+ NbtConfig.pRefreshTimer = NULL;
+ NbtConfig.pRemoteHashTimer = NULL;
+ NbtConfig.pSessionKeepAliveTimer = NULL;
+ NbtConfig.RefreshDivisor = REFRESH_DIVISOR;
+
+ if ( !NT_SUCCESS( status ) )
+ return status ;
+
+ // start a Timer to refresh names with the name service
+ //
+ if (!(NodeType & BNODE))
+ {
+
+ // the initial refresh rate until we can contact the name server
+ NbtConfig.MinimumTtl = NbtConfig.InitialRefreshTimeout;
+ NbtConfig.sTimeoutCount = 0;
+
+ status = StartTimer(
+ NbtConfig.InitialRefreshTimeout/REFRESH_DIVISOR,
+ NULL, // context value
+ NULL, // context2 value
+ RefreshTimeout,
+ NULL,
+ NULL,
+ 0,
+ &pTimerEntry);
+
+ if ( !NT_SUCCESS( status ) )
+ return status ;
+
+ NbtConfig.pRefreshTimer = pTimerEntry;
+ }
+
+ // calculate the count necessary to timeout out names in RemoteHashTimeout
+ // milliseconds
+ //
+ NbtConfig.RemoteTimeoutCount = (USHORT)((NbtConfig.RemoteHashTimeout/REMOTE_HASH_TIMEOUT));
+ if (NbtConfig.RemoteTimeoutCount == 0)
+ {
+ NbtConfig.RemoteTimeoutCount = 1;
+ }
+
+ // start a Timer to timeout remote cached names from the Remote hash table.
+ // The timer is a one minute timer, and the hash entries count down to zero
+ // then time out.
+ //
+ status = StartTimer(
+ REMOTE_HASH_TIMEOUT,
+ NULL, // context value
+ NULL, // context2 value
+ RemoteHashTimeout, // timer expiry routine
+ NULL,
+ NULL,
+ 0,
+ &pTimerEntry);
+
+
+ if ( !NT_SUCCESS( status ) )
+ {
+ StopInitTimers();
+ return status ;
+ }
+
+ NbtConfig.pRemoteHashTimer = pTimerEntry;
+
+ // start a Timer for Session Keep Alives which sends a session keep alive
+ // on a connection if the timer value is not set to -1
+ //
+ if (NbtConfig.KeepAliveTimeout != -1)
+ {
+ status = StartTimer(
+ NbtConfig.KeepAliveTimeout,
+ NULL, // context value
+ NULL, // context2 value
+ SessionKeepAliveTimeout, // timer expiry routine
+ NULL,
+ NULL,
+ 0,
+ &pTimerEntry);
+
+ if ( !NT_SUCCESS( status ) )
+ {
+ StopInitTimers();
+ return status ;
+ }
+
+ NbtConfig.pSessionKeepAliveTimer = pTimerEntry;
+ }
+
+
+
+ return(STATUS_SUCCESS);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+StopInitTimers(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This is stops the timers started in InitTimerNotOS
+
+Arguments:
+
+Return Value:
+
+ NTSTATUS - The function value is the final status from the initialization
+ operation.
+
+--*/
+
+{
+ CTEPagedCode();
+
+ if (NbtConfig.pRefreshTimer)
+ {
+ StopTimer(NbtConfig.pRefreshTimer,NULL,NULL);
+ }
+ if (NbtConfig.pSessionKeepAliveTimer)
+ {
+ StopTimer(NbtConfig.pSessionKeepAliveTimer,NULL,NULL);
+ }
+ if (NbtConfig.pRemoteHashTimer)
+ {
+ StopTimer(NbtConfig.pRemoteHashTimer,NULL,NULL);
+ }
+ return(STATUS_SUCCESS);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+ReadParameters(
+ IN tNBTCONFIG *pConfig,
+ IN HANDLE ParmHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to read various parameters from the parameters
+ section of the NBT section of the registry.
+
+Arguments:
+
+ pConfig - A pointer to the configuration data structure.
+ ParmHandle - a handle to the parameters Key under Nbt
+
+Return Value:
+
+ Status
+
+--*/
+
+{
+ ULONG NodeSize;
+ ULONG Refresh;
+
+ CTEPagedCode();
+
+ ReadParameters2(pConfig, ParmHandle);
+
+ pConfig->NameServerPort = (USHORT)CTEReadSingleIntParameter(ParmHandle,
+ WS_NS_PORT_NUM,
+ NBT_NAMESERVER_UDP_PORT,
+ 0);
+#ifdef VXD
+ pConfig->DnsServerPort = (USHORT)CTEReadSingleIntParameter(ParmHandle,
+ WS_DNS_PORT_NUM,
+ NBT_DNSSERVER_UDP_PORT,
+ 0);
+
+ pConfig->lRegistryMaxNames = (USHORT)CTEReadSingleIntParameter( NULL,
+ VXD_NAMETABLE_SIZE_NAME,
+ VXD_DEF_NAMETABLE_SIZE,
+ VXD_MIN_NAMETABLE_SIZE ) ;
+
+ pConfig->lRegistryMaxSessions = (USHORT)CTEReadSingleIntParameter( NULL,
+ VXD_SESSIONTABLE_SIZE_NAME,
+ VXD_DEF_SESSIONTABLE_SIZE,
+ VXD_MIN_SESSIONTABLE_SIZE ) ;
+
+
+#endif
+
+ pConfig->RemoteHashTimeout = CTEReadSingleIntParameter(ParmHandle,
+ WS_CACHE_TIMEOUT,
+ DEFAULT_CACHE_TIMEOUT,
+ MIN_CACHE_TIMEOUT);
+ pConfig->InitialRefreshTimeout = CTEReadSingleIntParameter(ParmHandle,
+ WS_INITIAL_REFRESH,
+ NBT_INITIAL_REFRESH_TTL,
+ NBT_INITIAL_REFRESH_TTL);
+
+ // retry timeouts and number of retries for both Broadcast name resolution
+ // and Name Service resolution
+ //
+ pConfig->uNumBcasts = (USHORT)CTEReadSingleIntParameter(ParmHandle,
+ WS_NUM_BCASTS,
+ DEFAULT_NUMBER_BROADCASTS,
+ 1);
+
+ pConfig->uBcastTimeout = CTEReadSingleIntParameter(ParmHandle,
+ WS_BCAST_TIMEOUT,
+ DEFAULT_BCAST_TIMEOUT,
+ MIN_BCAST_TIMEOUT);
+
+ pConfig->uNumRetries = (USHORT)CTEReadSingleIntParameter(ParmHandle,
+ WS_NAMESRV_RETRIES,
+ DEFAULT_NUMBER_RETRIES,
+ 1);
+
+ pConfig->uRetryTimeout = CTEReadSingleIntParameter(ParmHandle,
+ WS_NAMESRV_TIMEOUT,
+ DEFAULT_RETRY_TIMEOUT,
+ MIN_RETRY_TIMEOUT);
+
+ pConfig->KeepAliveTimeout = CTEReadSingleIntParameter(ParmHandle,
+ WS_KEEP_ALIVE,
+ DEFAULT_KEEP_ALIVE,
+ MIN_KEEP_ALIVE);
+
+ pConfig->SelectAdapter = (BOOLEAN)CTEReadSingleIntParameter(ParmHandle,
+ WS_RANDOM_ADAPTER,
+ 0,
+ 0);
+ pConfig->SingleResponse = (BOOLEAN)CTEReadSingleIntParameter(ParmHandle,
+ WS_SINGLE_RESPONSE,
+ 0,
+ 0);
+ pConfig->ResolveWithDns = (BOOLEAN)CTEReadSingleIntParameter(ParmHandle,
+ WS_ENABLE_DNS,
+ 0,
+ 0);
+ pConfig->TryAllAddr = (BOOLEAN)CTEReadSingleIntParameter(ParmHandle,
+ WS_TRY_ALL_ADDRS,
+ 1,
+ 1); // enabled by default
+ pConfig->LmHostsTimeout = CTEReadSingleIntParameter(ParmHandle,
+ WS_LMHOSTS_TIMEOUT,
+ DEFAULT_LMHOST_TIMEOUT,
+ MIN_LMHOST_TIMEOUT);
+ pConfig->MaxDgramBuffering = CTEReadSingleIntParameter(ParmHandle,
+ WS_MAX_DGRAM_BUFFER,
+ DEFAULT_DGRAM_BUFFERING,
+ DEFAULT_DGRAM_BUFFERING);
+
+ pConfig->EnableProxyRegCheck = (BOOLEAN)CTEReadSingleIntParameter(ParmHandle,
+ WS_ENABLE_PROXY_REG_CHECK,
+ 0,
+ 0);
+
+ pConfig->WinsDownTimeout = (ULONG)CTEReadSingleIntParameter(ParmHandle,
+ WS_WINS_DOWN_TIMEOUT,
+ DEFAULT_WINS_DOWN_TIMEOUT,
+ MIN_WINS_DOWN_TIMEOUT);
+
+ pConfig->MaxBackLog = (ULONG)CTEReadSingleIntParameter(ParmHandle,
+ WS_MAX_CONNECTION_BACKLOG,
+ DEFAULT_CONN_BACKLOG,
+ MIN_CONN_BACKLOG);
+
+ pConfig->SpecialConnIncrement = (ULONG)CTEReadSingleIntParameter(ParmHandle,
+ WS_CONNECTION_BACKLOG_INCREMENT,
+ DEFAULT_CONN_BACKLOG_INCREMENT,
+ MIN_CONN_BACKLOG_INCREMENT);
+
+ //
+ // Cap the upper limit
+ //
+ if (pConfig->MaxBackLog > MAX_CONNECTION_BACKLOG) {
+ pConfig->MaxBackLog = MAX_CONNECTION_BACKLOG;
+ }
+
+ if (pConfig->SpecialConnIncrement > MAX_CONNECTION_BACKLOG_INCREMENT) {
+ pConfig->SpecialConnIncrement = MAX_CONNECTION_BACKLOG_INCREMENT;
+ }
+
+
+ //
+ // Since UB chose the wrong opcode (9) we have to allow configuration
+ // of that opcode incase our nodes refresh to their NBNS
+ //
+ Refresh = (ULONG)CTEReadSingleIntParameter(ParmHandle,
+ WS_REFRESH_OPCODE,
+ REFRESH_OPCODE,
+ REFRESH_OPCODE);
+ if (Refresh == UB_REFRESH_OPCODE)
+ {
+ pConfig->OpRefresh = OP_REFRESH_UB;
+ }
+ else
+ {
+ pConfig->OpRefresh = OP_REFRESH;
+ }
+
+#ifndef VXD
+ pConfig->EnableLmHosts = (BOOLEAN)CTEReadSingleIntParameter(ParmHandle,
+ WS_ENABLE_LMHOSTS,
+ 0,
+ 0);
+#endif
+
+#ifdef PROXY_NODE
+
+ {
+ ULONG Proxy;
+ Proxy = CTEReadSingleIntParameter(ParmHandle,
+ WS_IS_IT_A_PROXY,
+ IS_NOT_PROXY, //default value
+ IS_NOT_PROXY);
+
+ //
+ // If the returned value is greater than IS_NOT_PROXY, it is a proxy
+ // (also check that they have not entered an ascii string instead of a
+ // dword in the registry
+ //
+ if ((Proxy > IS_NOT_PROXY) && (Proxy < ('0'+IS_NOT_PROXY)))
+ {
+ NodeType |= PROXY;
+ }
+ }
+#endif
+ NodeSize = CTEReadSingleIntParameter(ParmHandle,
+ WS_NODE_SIZE,
+ NodeType & PROXY ? LARGE : DEFAULT_NODE_SIZE,
+ NodeType & PROXY ? LARGE : SMALL);
+
+ switch (NodeSize)
+ {
+ default:
+ case SMALL:
+
+ pConfig->uNumLocalNames = NUMBER_LOCAL_NAMES;
+ pConfig->uNumRemoteNames = NUMBER_REMOTE_NAMES;
+ pConfig->uNumBucketsLocal = NUMBER_BUCKETS_LOCAL_HASH_TABLE;
+ pConfig->uNumBucketsRemote = NUMBER_BUCKETS_REMOTE_HASH_TABLE;
+
+ pConfig->iMaxNumBuff[eNBT_DGRAM_TRACKER] = NBT_NUM_DGRAM_TRACKERS;
+ pConfig->iMaxNumBuff[eNBT_TIMER_ENTRY] = TIMER_Q_SIZE;
+#ifndef VXD
+ pConfig->iMaxNumBuff[eNBT_FREE_IRPS] = NBT_NUM_IRPS;
+ pConfig->iMaxNumBuff[eNBT_DGRAM_MDLS] = NBT_NUM_DGRAM_MDLS;
+ pConfig->iMaxNumBuff[eNBT_FREE_SESSION_MDLS] = NBT_NUM_SESSION_MDLS;
+#else
+ pConfig->iMaxNumBuff[eNBT_SESSION_HDR] = NBT_NUM_SESSION_HDR ;
+ pConfig->iMaxNumBuff[eNBT_SEND_CONTEXT] = NBT_NUM_SEND_CONTEXT ;
+ pConfig->iMaxNumBuff[eNBT_RCV_CONTEXT] = NBT_NUM_RCV_CONTEXT ;
+#endif
+ break;
+
+ case MEDIUM:
+
+ pConfig->uNumLocalNames = MEDIUM_NUMBER_LOCAL_NAMES;
+ pConfig->uNumRemoteNames = MEDIUM_NUMBER_REMOTE_NAMES;
+ pConfig->uNumBucketsLocal = MEDIUM_NUMBER_BUCKETS_LOCAL_HASH_TABLE;
+ pConfig->uNumBucketsRemote = MEDIUM_NUMBER_BUCKETS_REMOTE_HASH_TABLE;
+
+ pConfig->iMaxNumBuff[eNBT_DGRAM_TRACKER] = MEDIUM_NBT_NUM_DGRAM_TRACKERS;
+ pConfig->iMaxNumBuff[eNBT_TIMER_ENTRY] = MEDIUM_TIMER_Q_SIZE;
+#ifndef VXD
+ pConfig->iMaxNumBuff[eNBT_FREE_IRPS] = MEDIUM_NBT_NUM_IRPS;
+ pConfig->iMaxNumBuff[eNBT_DGRAM_MDLS] = MEDIUM_NBT_NUM_DGRAM_MDLS;
+ pConfig->iMaxNumBuff[eNBT_FREE_SESSION_MDLS] = MEDIUM_NBT_NUM_SESSION_MDLS;
+#else
+ pConfig->iMaxNumBuff[eNBT_SESSION_HDR] = MEDIUM_NBT_NUM_SESSION_HDR ;
+ pConfig->iMaxNumBuff[eNBT_SEND_CONTEXT] = MEDIUM_NBT_NUM_SEND_CONTEXT ;
+ pConfig->iMaxNumBuff[eNBT_RCV_CONTEXT] = MEDIUM_NBT_NUM_RCV_CONTEXT ;
+#endif
+ break;
+
+ case LARGE:
+
+ pConfig->uNumLocalNames = LARGE_NUMBER_LOCAL_NAMES;
+ pConfig->uNumRemoteNames = LARGE_NUMBER_REMOTE_NAMES;
+ pConfig->uNumBucketsLocal = LARGE_NUMBER_BUCKETS_LOCAL_HASH_TABLE;
+ pConfig->uNumBucketsRemote = LARGE_NUMBER_BUCKETS_REMOTE_HASH_TABLE;
+
+ pConfig->iMaxNumBuff[eNBT_DGRAM_TRACKER] = LARGE_NBT_NUM_DGRAM_TRACKERS;
+ pConfig->iMaxNumBuff[eNBT_TIMER_ENTRY] = LARGE_TIMER_Q_SIZE;
+#ifndef VXD
+ pConfig->iMaxNumBuff[eNBT_FREE_IRPS] = LARGE_NBT_NUM_IRPS;
+ pConfig->iMaxNumBuff[eNBT_DGRAM_MDLS] = LARGE_NBT_NUM_DGRAM_MDLS;
+ pConfig->iMaxNumBuff[eNBT_FREE_SESSION_MDLS] = LARGE_NBT_NUM_SESSION_MDLS;
+#else
+ pConfig->iMaxNumBuff[eNBT_SESSION_HDR] = LARGE_NBT_NUM_SESSION_HDR ;
+ pConfig->iMaxNumBuff[eNBT_SEND_CONTEXT] = LARGE_NBT_NUM_SEND_CONTEXT ;
+ pConfig->iMaxNumBuff[eNBT_RCV_CONTEXT] = LARGE_NBT_NUM_RCV_CONTEXT ;
+#endif
+ break;
+ }
+
+ ReadLmHostFile(pConfig,ParmHandle);
+}
+
+#ifdef VXD
+#pragma END_INIT
+#endif
+
+//----------------------------------------------------------------------------
+ VOID
+ReadParameters2(
+ IN tNBTCONFIG *pConfig,
+ IN HANDLE ParmHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to read DHCPable parameters from the parameters
+ section of the NBT section of the registry.
+
+ This routine is primarily for the Vxd.
+
+Arguments:
+
+ pConfig - A pointer to the configuration data structure.
+ ParmHandle - a handle to the parameters Key under Nbt
+
+Return Value:
+
+ Status
+
+--*/
+
+{
+ ULONG Node;
+ ULONG ReadOne;
+ ULONG ReadTwo;
+
+ CTEPagedCode();
+
+ Node = CTEReadSingleIntParameter(ParmHandle, // handle of key to look under
+ WS_NODE_TYPE, // wide string name
+ 0, // default value
+ 0);
+
+ switch (Node)
+ {
+ case 2:
+ NodeType = PNODE;
+ break;
+
+ case 4:
+ NodeType = MNODE;
+ break;
+
+ case 8:
+ NodeType = MSNODE;
+ break;
+
+ case 1:
+ NodeType = BNODE;
+ break;
+
+ default:
+ NodeType = BNODE | DEFAULT_NODE_TYPE;
+ break;
+ }
+
+ // do a trick here - read the registry twice for the same value, passing
+ // in two different defaults, in order to determine if the registry
+ // value has been defined or not - since it may be defined, but equal
+ // to one default.
+ ReadOne = CTEReadSingleHexParameter(ParmHandle,
+ WS_ALLONES_BCAST,
+ DEFAULT_BCAST_ADDR,
+ 0);
+ ReadTwo = CTEReadSingleHexParameter(ParmHandle,
+ WS_ALLONES_BCAST,
+ 0,
+ 0);
+ if (ReadOne != ReadTwo)
+ {
+ NbtConfig.UseRegistryBcastAddr = FALSE;
+ }
+ else
+ {
+ NbtConfig.UseRegistryBcastAddr = TRUE;
+ NbtConfig.RegistryBcastAddr = ReadTwo;
+ }
+
+ ReadScope(pConfig,ParmHandle);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+ReadScope(
+ IN tNBTCONFIG *pConfig,
+ IN HANDLE ParmHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to read the scope from registry and convert it to
+ a format where the intervening dots are length bytes.
+
+Arguments:
+
+ pConfig - A pointer to the configuration data structure.
+ ParmHandle - a handle to the parameters Key under Nbt
+
+Return Value:
+
+ Status
+
+--*/
+
+{
+ NTSTATUS status;
+ PUCHAR pScope;
+ PUCHAR pBuff;
+ PUCHAR pBuffer;
+ PUCHAR period;
+ ULONG Len;
+ UCHAR Chr;
+
+
+ CTEPagedCode();
+ //
+ // this routine returns the scope in a dotted format.
+ // "Scope.MoreScope.More" The dots are
+ // converted to byte lengths by the code below. This routine allocates
+ // the memory for the pScope string.
+ //
+ status = CTEReadIniString(ParmHandle,NBT_SCOPEID,&pBuffer);
+
+
+ if (NT_SUCCESS(status) && strlen(pBuffer) > 0 )
+ {
+ //
+ // the user can type in an * to indicate that they really want
+ // a null scope and that should override the DHCP scope. So check
+ // here for an * and if so, set the scope back to null.
+ //
+ if (pBuffer[0] == '*')
+ {
+ pBuffer[0] = 0;
+ }
+ // length of scope is num chars plus the 0 on the end, plus
+ // the length byte on the start(+2 total) - so allocate another buffer
+ // that is one longer than the previous one so it can include
+ // these extra two bytes.
+ //
+ Len = strlen(pBuffer);
+ //
+ // the scope cannot be longer than 255 characters as per RFC1002
+ //
+ if (Len <= MAX_SCOPE_LENGTH)
+ {
+ pScope = CTEAllocInitMem(Len+2);
+ if (pScope)
+ {
+ CTEMemCopy((pScope+1),pBuffer,Len);
+
+ //
+ // Put an null on the end of the scope
+ //
+ pScope[Len+1] = 0;
+
+ Len = 1;
+
+ // now go through the string converting periods to length
+ // bytes - we know the first byte is a length byte so skip it.
+ //
+ pBuff = pScope;
+ pBuff++;
+ Len++;
+ period = pScope;
+ while (Chr = *pBuff)
+ {
+ Len++;
+ if (Chr == '.')
+ {
+ *period = pBuff - period - 1;
+
+ //
+ // Each label can be at most 63 bytes long
+ //
+ if (*period > MAX_LABEL_LENGTH)
+ {
+ status = STATUS_UNSUCCESSFUL;
+ NbtLogEvent(EVENT_SCOPE_LABEL_TOO_LONG,STATUS_SUCCESS);
+ break;
+ }
+
+ // check for two periods back to back and use no scope if this
+ // happens
+ if (*period == 0)
+ {
+ status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ period = pBuff++;
+ }
+ else
+ pBuff++;
+ }
+ if (NT_SUCCESS(status))
+ {
+ // the last ptr is always the end of the name.
+
+ *period = (UCHAR)(pBuff - period -1);
+
+ pConfig->ScopeLength = (USHORT)Len;
+ pConfig->pScope = pScope;
+ CTEMemFree(pBuffer);
+ return;
+ }
+ CTEMemFree(pScope);
+ }
+ CTEMemFree(pBuffer);
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ NbtLogEvent(EVENT_SCOPE_LABEL_TOO_LONG,STATUS_SUCCESS);
+ }
+
+ }
+
+
+ //
+ // the scope is one byte => '\0' - the length of the root name (zero)
+ //
+ pConfig->ScopeLength = 1;
+ //
+ // Since this routine could be called again after startup when a new
+ // DHCP address is used, we may have to free the old scope memory
+ //
+ if (pConfig->pScope)
+ {
+ CTEMemFree(pConfig->pScope);
+ }
+ pConfig->pScope = CTEAllocInitMem(1);
+ *pConfig->pScope = '\0';
+
+}
+
+#ifdef VXD
+#pragma BEGIN_INIT
+#endif
+
+//----------------------------------------------------------------------------
+ VOID
+ReadLmHostFile(
+ IN tNBTCONFIG *pConfig,
+ IN HANDLE ParmHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to read the lmhost file path from the registry.
+
+Arguments:
+
+ pConfig - A pointer to the configuration data structure.
+ ParmHandle - a handle to the parameters Key under Nbt
+
+Return Value:
+
+ Status
+
+--*/
+
+{
+ NTSTATUS status;
+ PUCHAR pBuffer;
+ PUCHAR pchr;
+
+ CTEPagedCode();
+
+ //
+ // If we get a new Dhcp address this routine will get called again
+ // after startup so we need to free any current lmhosts file path
+ //
+ if (pConfig->pLmHosts)
+ {
+ CTEMemFree(pConfig->pLmHosts);
+ }
+ //
+ // read in the LmHosts File location
+ //
+#ifdef VXD
+ status = CTEReadIniString(ParmHandle,WS_LMHOSTS_FILE,&pBuffer);
+#else
+ status = NTGetLmHostPath(&pBuffer);
+#endif
+
+ if (NT_SUCCESS(status))
+ {
+ NbtConfig.pLmHosts = pBuffer;
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:LmHostsFile path is %s\n",NbtConfig.pLmHosts));
+
+ // find the last backslash so we can calculate the file path length
+ //
+ pchr = strrchr(pBuffer,'\\');
+ if (pchr)
+ {
+ NbtConfig.PathLength = pchr - pBuffer + 1; // include backslash in length
+ }
+ else
+ {
+ //
+ // the lm host file must include a path of at least "c:\" i.e.
+ // the registry contains c:\lmhost, otherwise NBT won't be
+ // able to find the file since it doesn't know what directory
+ // to look in.
+ //
+ NbtConfig.pLmHosts = NULL;
+ NbtConfig.PathLength = 0;
+ }
+
+ }
+ else
+ {
+ NbtConfig.pLmHosts = NULL;
+ NbtConfig.PathLength = 0;
+ }
+}
+#ifdef VXD
+#pragma END_INIT
+#endif
+
+
diff --git a/private/ntos/nbt/nbt/makefile.16 b/private/ntos/nbt/nbt/makefile.16
new file mode 100644
index 000000000..1cfc07a9f
--- /dev/null
+++ b/private/ntos/nbt/nbt/makefile.16
@@ -0,0 +1,109 @@
+#
+#
+# Make file for Name server VxD.
+#
+# Have to have lots of stuff defined for this makefile to work.
+#
+#
+#
+
+ROOTDIR=..
+!include ..\rules16.mk
+
+NBTSRC=$(ROOTDIR)\nbt
+NBTOBJD=$(NBTSRC)\nodebug
+NBTDOBJD=$(NBTSRC)\debug
+
+NBTOBJS= $(NBTOBJD)\hashtbl.obj\
+ $(NBTOBJD)\hndlrs.obj\
+ $(NBTOBJD)\inbound.obj\
+ $(NBTOBJD)\name.obj\
+ $(NBTOBJD)\namesrv.obj\
+ $(NBTOBJD)\nbtutils.obj\
+ $(NBTOBJD)\proxy.obj\
+ $(NBTOBJD)\timer.obj\
+ $(NBTOBJD)\udpsend.obj\
+ $(NBTOBJD)\init.obj\
+ $(NBTOBJD)\parse.obj
+
+NBTDOBJS=$(NBTOBJS:nodebug=debug)
+
+VTSF1=$(NBTSRC:\=/)
+VTSF=$(VTSF1:.=\.)
+
+#
+# Hack: Each .obj must begin with "..". Here we replace ".." with "+.."
+# because the 16bit lib utility requires the operation to come before the
+# obj.
+#
+
+NBTLIBOBJS=$(NBTOBJS:..=+..)
+NBTLIBDOBJS=$(NBTDOBJS:..=+..)
+
+NBTCFLAGS= -c -DVXD -Zp1l -G3 -Owx -nologo -D_X86_=1 -Di386=1 -DDEVL=1 -DPROXY_NODE
+NBTCINC=$(TCP)\h;$(NDIS3)\inc;$(WIN32INC);$(BASEDIR)\public\sdk\inc;$(BASEDIR)\public\sdk\inc\crt;..\inc;..\..\inc;..\..\..\inc;..\..\..\..\inc;$(BASEDIR)\public\oak\inc
+NBT16CINC=
+
+
+{$(NBTSRC)}.c{$(NBTOBJD)}.obj:
+ set INCLUDE=$(NBTCINC)
+ set CL=$(NBTCFLAGS)
+ $(CL386) -Fo$(NBTOBJD)\$(@B).obj $(NBTSRC)\$(@B).c
+
+{$(NBTSRC)}.c{$(NBTDOBJD)}.obj:
+ set INCLUDE=$(NBTCINC)
+ set CL=$(NBTCFLAGS) -DDEBUG -Oy- -Zd
+ $(CL386) -Fo$(NBTDOBJD)\$(@B).obj $(NBTSRC)\$(@B).c
+
+all: NBT NBTD
+
+debug: NBTD
+
+NBT: $(NBTOBJD)\nbt.lib
+
+NBTD: $(NBTDOBJD)\nbt.lib
+
+clean:
+ -del $(NBTDOBJD)\*.obj
+ -del $(NBTDOBJD)\*.lib
+ -del $(NBTOBJD)\*.obj
+ -del $(NBTOBJD)\*.lib
+
+$(NBTOBJD)\NBT.LIB: $(NBTOBJS)
+ -del $(NBTOBJD)\NBT.LIB
+ $(LIBUTIL) @<<
+$(NBTOBJD)\NBT.LIB
+y
+$(NBTLIBOBJS)
+;
+<<
+
+
+$(NBTDOBJD)\NBT.LIB: $(NBTDOBJS)
+ -del $(NBTDOBJD)\NBT.LIB
+ $(LIBUTIL) @<<
+$(NBTDOBJD)\NBT.LIB
+y
+$(NBTLIBDOBJS)
+;
+<<
+
+
+
+depend: $(NBTBINCS)
+ -copy $(NBTSRC)\depend.mk $(NBTSRC)\depend.old
+ echo #******************************************************************** > $(NBTSRC)\depend.mk
+ echo #** Copyright(c) Microsoft Corp., 1992 ** >> $(NBTSRC)\depend.mk
+ echo #******************************************************************** >> $(NBTSRC)\depend.mk
+ set INCLUDE=$(NBTCINC)
+ -$(INCLUDES) -i -e -S$$(NBTOBJD) -S$$(NBTDOBJD) -sobj $(NBTSRC)\*.c >> $(NBTSRC)\depend.mk
+ $(SED) -e s`$(IMPF)`$$(IMPORT)`g <$(NBTSRC)\depend.mk >$(NBTSRC)\depend.tmp
+ $(SED) -e s`$(CMNF)`$$(COMMON)`g <$(NBTSRC)\depend.tmp >$(NBTSRC)\depend.mk
+ $(SED) -e s`$(VTSF)`$$(NBTSRC)`g <$(NBTSRC)\depend.mk >$(NBTSRC)\depend.tmp
+ $(SED) -e s`$(BASEDIRF)`$$(BASEDIR)`g <$(NBTSRC)\depend.tmp > $(NBTSRC)\depend.mk
+ $(SED) -e s`$(INCF)`$$(INC)`g <$(NBTSRC)\depend.mk >$(NBTSRC)\depend.tmp
+ $(SED) -e s`$(HF)`$$(H)`g <$(NBTSRC)\depend.tmp >$(NBTSRC)\depend.mk
+ -del $(NBTSRC)\depend.tmp
+
+!include depend.mk
+
diff --git a/private/ntos/nbt/nbt/mp/makefile b/private/ntos/nbt/nbt/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/nbt/nbt/mp/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/nbt/nbt/mp/sources b/private/ntos/nbt/nbt/mp/sources
new file mode 100644
index 000000000..301687c9a
--- /dev/null
+++ b/private/ntos/nbt/nbt/mp/sources
@@ -0,0 +1,27 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+!include ..\sources.inc
diff --git a/private/ntos/nbt/nbt/name.c b/private/ntos/nbt/nbt/name.c
new file mode 100644
index 000000000..70a2c2dc4
--- /dev/null
+++ b/private/ntos/nbt/nbt/name.c
@@ -0,0 +1,10345 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Name.c
+
+Abstract:
+
+ This file implements Tdi interface into the Top of NBT. In the NT
+ implementation, ntisol.c calls these routines after extracting the
+ relevent information from the Irp passed in from the Io subsystem.
+
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h" // procedure headings
+#ifndef VXD
+
+#include <nbtioctl.h>
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+#endif
+//
+// Allocate storage for the configuration information and setup a ptr to
+// it.
+//
+tNBTCONFIG NbtConfig;
+tNBTCONFIG *pNbtGlobConfig = &NbtConfig;
+BOOLEAN CachePrimed;
+
+//
+// This structure is used to store name query and registration statistics
+//
+tNAMESTATS_INFO NameStatsInfo;
+#ifndef VXD
+//
+// this tracks the original File system process that Nbt was booted by, so
+// that handles can be created and destroyed in that process
+//
+PEPROCESS NbtFspProcess;
+#endif
+//
+// this describes whether we are a Bnode, Mnode, MSnode or Pnode
+//
+USHORT NodeType;
+//
+// this is used to track the memory allocated for datagram sends
+//
+ULONG NbtMemoryAllocated;
+
+// this is used to track used trackers to help solve cases where they all
+// are used.
+//
+//#if DBG
+
+LIST_ENTRY UsedTrackers;
+
+//#endif
+
+#ifdef VXD
+ULONG DefaultDisconnectTimeout;
+#else
+LARGE_INTEGER DefaultDisconnectTimeout;
+#endif
+
+// ************* REMOVE LATER *****************88
+BOOLEAN StreamsStack;
+
+//
+// Function prototypes for functions local to this file
+//
+VOID
+LockedRemoveFromList(
+ IN tCONNECTELE *pConnEle,
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+VOID
+CleanupFromRegisterFailed(
+ IN PUCHAR pNameRslv,
+ IN tCLIENTELE *pClientEle
+ );
+
+VOID
+SendDgramContinue(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ );
+
+VOID
+CTECountedAllocMem(
+ PVOID *pBuffer,
+ ULONG Size
+ );
+
+VOID
+CTECountedFreeMem(
+ PVOID pBuffer,
+ ULONG Size
+ );
+
+VOID
+SendDgramCompletion(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo);
+
+VOID
+DgramSendCleanupTracker(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN NTSTATUS status,
+ IN ULONG Length
+ );
+
+VOID
+SessionSetupContinue(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ );
+VOID
+SessionStartupContinue(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo);
+VOID
+SessionStartupCompletion(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo);
+
+
+VOID
+SendNodeStatusContinue(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ );
+
+
+NTSTATUS
+SendToResolvingName(
+ IN tNAMEADDR *pNameAddr,
+ IN PCHAR pName,
+ IN CTELockHandle OldIrq,
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PVOID QueryCompletion
+ );
+
+NTSTATUS
+StartSessionTimer(
+ tDGRAM_SEND_TRACKING *pTracker,
+ tCONNECTELE *pConnEle
+ );
+
+VOID
+SessionTimedOut(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+VOID
+QueryNameCompletion(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ );
+
+NTSTATUS
+FindNameOrQuery(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PUCHAR pName,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID QueryCompletion,
+ IN tDGRAM_SEND_TRACKING **ppTracker,
+ IN BOOLEAN DgramSend,
+ OUT tNAMEADDR **pNameAddr
+ );
+
+tNAMEADDR *
+FindNameRemoteThenLocal(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ OUT PULONG plNameType
+ );
+
+VOID
+FreeTracker(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN ULONG Actions
+ );
+
+VOID
+WipeOutLowerconn(
+ IN PVOID pContext
+ );
+
+#ifdef RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+VOID
+NbtRetryPreConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ );
+
+VOID
+NbtCancelPreConnect(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+
+VOID
+NbtRetryPostConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ );
+
+BOOLEAN
+NbtAttemptAutoDial(
+ IN tCONNECTELE *pConnEle,
+ IN PVOID pTimeout,
+ IN PTDI_CONNECTION_INFORMATION pCallInfo,
+ IN PTDI_CONNECTION_INFORMATION pReturnInfo,
+ IN PIRP pIrp,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc
+ );
+
+VOID
+NbtNoteNewConnection(
+ IN tCONNECTELE *pConnEle,
+ IN tNAMEADDR *pNameAddr
+ );
+#endif // RASAUTODIAL
+
+NTSTATUS
+NbtConnectCommon(
+ IN TDI_REQUEST *pRequest,
+ IN PVOID pTimeout,
+ IN PTDI_CONNECTION_INFORMATION pCallInfo,
+ IN PTDI_CONNECTION_INFORMATION pReturnInfo,
+ IN PIRP pIrp
+ );
+
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, NbtOpenConnection)
+#pragma CTEMakePageable(PAGE, NbtOpenAndAssocConnection)
+#pragma CTEMakePageable(PAGE, NbtSendDatagram)
+#pragma CTEMakePageable(PAGE, BuildSendDgramHdr)
+#pragma CTEMakePageable(PAGE, NbtResyncRemoteCache)
+#pragma CTEMakePageable(PAGE, NbtQueryFindName)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtOpenAddress(
+ IN TDI_REQUEST *pRequest,
+ IN TA_ADDRESS UNALIGNED *pTaAddress,
+ IN ULONG IpAddress,
+ IN PVOID pSecurityDescriptor,
+ IN tDEVICECONTEXT *pContext,
+ IN PVOID pIrp)
+/*++
+Routine Description:
+
+ This Routine handles opening an address for a Client.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ tADDRESSELE *pAddrElement;
+ tCLIENTELE *pClientEle;
+ USHORT uAddrType;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ PCHAR pNameRslv;
+ tNAMEADDR *pNameAddr;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+ tTIMERQENTRY *pTimer;
+ BOOLEAN ReRegister;
+ BOOLEAN MultiHomedReRegister;
+ BOOLEAN DontIncrement= FALSE;
+ ULONG TdiAddressType;
+
+
+ ASSERT(pTaAddress);
+ if (!IpAddress)
+ {
+ //
+ // when there is no ip address yet, use the Loop back address as
+ // a default rather than null, since null tells NbtRegisterName
+ // that the address is already in the name table and it only needs
+ // to be reregistered.
+ //
+ IpAddress = LOOP_BACK;
+ }
+
+
+ TdiAddressType = pTaAddress->AddressType;
+ switch (TdiAddressType) {
+ case TDI_ADDRESS_TYPE_NETBIOS:
+ {
+ PTDI_ADDRESS_NETBIOS pNetbiosAddress = (PTDI_ADDRESS_NETBIOS)pTaAddress->Address;
+
+ uAddrType = pNetbiosAddress->NetbiosNameType;
+ pNameRslv = (PCHAR)pNetbiosAddress->NetbiosName;
+ }
+ break;
+ case TDI_ADDRESS_TYPE_NETBIOS_EX:
+ {
+ // The NETBIOS_EX address passed in will have two components,
+ // an Endpoint name as well as the NETBIOS address.
+ // In this implementation we ignore the second
+ // component and register the Endpoint name as a netbios
+ // address.
+
+ PTDI_ADDRESS_NETBIOS_EX pNetbiosExAddress = (PTDI_ADDRESS_NETBIOS_EX)pTaAddress->Address;
+
+ uAddrType = TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE;
+ pNameRslv = (PCHAR)pNetbiosExAddress->EndpointName;
+ }
+ break;
+ default:
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ // check for a zero length address, because this means that the
+ // client wants to receive "Netbios Broadcasts" which are names
+ // that start with "*...." ( and 15 0x00's ). However they should have
+ // queried the broadcast address with NBT which would have returned
+ // "*....'
+ //
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Registering name = %16.16s<%X>\n",pNameRslv,pNameRslv[15]));
+
+ //
+ // be sure the broadcast name has 15 zeroes after it
+ //
+ if ((pNameRslv[0] == '*') && (TdiAddressType == TDI_ADDRESS_TYPE_NETBIOS))
+ {
+ CTEZeroMemory(&pNameRslv[1],NETBIOS_NAME_SIZE-1);
+ }
+ // this synchronizes access to the local name table when a new name
+ // is registered. Basically it will not let the second registrant through
+ // until the first has put the name into the local table (i.e.
+ // NbtRegisterName has returned )
+ //
+ CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
+
+ // see if the name is registered on the local node.. we call the hash
+ // table function directly rather than using findname, because find name
+ // checks the state of the name too. We want to know if the name is in
+ // the table at all, and don't care if it is still resolving.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pNameAddr = NULL;
+ status = FindInHashTable(
+ pNbtGlobConfig->pLocalHashTbl,
+ pNameRslv,
+ NbtConfig.pScope,
+ &pNameAddr);
+
+
+ //
+ // the name could be in the hash table, but the address element deleted
+ //
+ if (!NT_SUCCESS(status) || !pNameAddr->pAddressEle)
+ {
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // open the name since it could not be found
+ //
+ // first of all allocate memory for the address block
+ //
+ pAddrElement = (tADDRESSELE *)NbtAllocMem(sizeof (tADDRESSELE),NBT_TAG('C'));
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ if (pAddrElement)
+ {
+ CTEZeroMemory(pAddrElement,sizeof(tADDRESSELE));
+ CTEInitLock(&pAddrElement->SpinLock);
+ pAddrElement->pDeviceContext = pContext;
+ pAddrElement->RefCount = 1;
+ pAddrElement->LockNumber = ADDRESS_LOCK;
+
+ pAddrElement->AddressType = TdiAddressType;
+
+ if ((uAddrType == NBT_UNIQUE ) || (uAddrType == NBT_QUICK_UNIQUE))
+ {
+ pAddrElement->NameType = NBT_UNIQUE;
+ }
+ else
+ {
+ pAddrElement->NameType = NBT_GROUP;;
+ }
+
+
+ // create client block and link to addresslist. This allows multiple
+ // clients to open the same address - for example a group name must
+ // be able to handle multiple clients, each receiving datagrams to it.
+ //
+ InitializeListHead(&pAddrElement->ClientHead);
+ pClientEle = NbtAllocateClientBlock(pAddrElement);
+
+ if (pClientEle)
+ {
+ pClientEle->AddressType = TdiAddressType;
+
+ // we need to track the Irp so that when the name registration
+ // completes, we can complete the Irp.
+ pClientEle->pIrp = pIrp;
+
+#ifndef VXD
+
+ // set the share access ( NT only ) - security descriptor stuff
+ if (pIrp)
+ {
+ status = NTSetSharedAccess(pContext,pIrp,pAddrElement);
+ }
+ else
+ status = STATUS_SUCCESS;
+
+ if (!NT_SUCCESS(status))
+ {
+ // unable to set the share access correctly so release the
+ // address object and the client block connected to it
+ NbtFreeAddressObj(pAddrElement);
+ NbtFreeClientObj(pClientEle);
+
+ goto ExitRoutine;
+
+ }
+
+#endif //!VXD
+
+ // pass back the client block address as a handle for future reference
+ // to the client
+ pRequest->Handle.AddressHandle = (PVOID)pClientEle;
+
+ pAddrElement->Verify = NBT_VERIFY_ADDRESS;
+
+ InitializeListHead(&pAddrElement->Linkage);
+
+ // keep track of which adapter this name is registered against.
+ pClientEle->pDeviceContext = (PVOID)pContext;
+
+ // fill in the context values passed back to the client. These must
+ // be done before the name is registered on the network because the
+ // registration can succeed (or fail) before this routine finishes).
+ // Since this routine can be called by NBT itself, pIrp may not be set,
+ // so check for it.
+ //
+ if (pIrp)
+ {
+#ifndef VXD
+ NTSetFileObjectContexts(
+ pClientEle->pIrp,(PVOID)pClientEle,
+ (PVOID)(NBT_ADDRESS_TYPE));
+#endif
+ }
+
+ // then add it to name service local name Q, passing the address of
+ // the block as a context value ( so that subsequent finds return the
+ // context value.
+ // we need to know if the name is a group name or a unique name.
+ // This registration may take some time so we return STATUS_PENDING
+ // to the client
+ //
+ if (pNameAddr)
+ {
+ //
+ // Write the correct Ip address to the table incase this
+ // was a group name and has now changed to a unique
+ // name, but don't overwrite a valid ip address with
+ // loopback
+ //
+ if (IpAddress != LOOP_BACK)
+ {
+ pNameAddr->IpAddress = IpAddress;
+ }
+
+ // need to tell NbtRegis... not to put the name in the hash table
+ // again
+ IpAddress = 0;
+ }
+
+ pAddrElement->RefCount++;
+
+ status = NbtRegisterName(
+ NBT_LOCAL,
+ IpAddress,
+ pNameRslv,
+ NbtConfig.pScope,
+ (PVOID)pClientEle, // context value
+ (PVOID)NbtRegisterCompletion, // completion routine for
+ uAddrType, // Name Srv to call
+ pContext);
+ //
+ // ret status could be either status pending or status success since Quick
+ // names return success - or status failure
+ //
+ if (NT_SUCCESS(status))
+ {
+ // link the address element to the head of the address list
+ // The Joint Lock protects this operation.
+ ExInterlockedInsertTailList(&NbtConfig.AddressHead,
+ &pAddrElement->Linkage,
+ &NbtConfig.JointLock.SpinLock);
+ NbtDereferenceAddress(pAddrElement);
+ }
+ else
+ {
+ NbtFreeClientObj(pClientEle);
+
+ NbtFreeAddressObj(pAddrElement);
+ }
+
+ } // if pClientEle
+ else
+ {
+ NbtFreeAddressObj(pAddrElement);
+ }
+
+ } // if pAddrElement
+
+ }
+ else
+ {
+ pAddrElement = (tADDRESSELE *)pNameAddr->pAddressEle;
+ //
+ // Write the correct Ip address to the table incase this
+ // was a group name and has now changed to a unique
+ // name, but don't overwrite with the loop back address because
+ // that means that the adapter does not have an address yet.
+ // For Group names the Ip address stays as 0, so we know to do a
+ // broadcast.
+ //
+ if ((IpAddress != LOOP_BACK) &&
+ (pNameAddr->NameTypeState & NAMETYPE_UNIQUE))
+ {
+ pNameAddr->IpAddress = IpAddress;
+ }
+
+ //
+ // increment here before releasing the spinlock so that a name
+ // release done cannot free pAddrElement.
+ //
+ CTEInterlockedIncrementLong(&pAddrElement->RefCount);
+#ifndef VXD
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // check the shared access of the name - this check must be done
+ // at Irl = 0, so no spin locks held
+ //
+
+ if (pIrp) {
+ status = NTCheckSharedAccess(
+ pContext,
+ pIrp,
+ (tADDRESSELE *)pNameAddr->pAddressEle);
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+#else
+ //
+ // For the Vxd, we don't allow multiple names in the local name table.
+ // In NT, this is prevented on a per process basis by the Netbios
+ // driver. If the name is being deregistered (conflict) then allow
+ // the client to reopen the name
+ //
+ if ( !(pNameAddr->NameTypeState & STATE_CONFLICT))
+ status = STATUS_UNSUCCESSFUL;
+#endif
+
+ // multihomed hosts register the same unique name on several adapters.
+ // NT DOES allow a client to share a unique name, so we must NOT
+ // run this next code if the NT check has passed!!
+ //
+ if (!NT_SUCCESS(status))
+ {
+ // if this is a unique name being registered on another adapter
+ // then allow it to occur - the assumption is that the same
+ // client is registering on more than one adapter all at once,
+ // rather than two different clients.
+ //
+ if ((NbtConfig.MultiHomed) &&
+ (!(pNameAddr->AdapterMask & pContext->AdapterNumber)))
+ {
+ status = STATUS_SUCCESS;
+ }
+ else
+ status = STATUS_UNSUCCESSFUL;
+
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // check if this is a client trying to add the permanent name,
+ // since that name will fail the security check
+ // We allow a single client to use the permanent name - since its
+ // a unique name it will fail the Vxd check too.
+ //
+ if (CTEMemEqu(&pNameAddr->Name[10],
+ &pContext->MacAddress.Address[0],
+ sizeof(tMAC_ADDRESS)))
+ {
+ // check if there is just one element on the client list. If so
+ // then the permanent name is not being used yet - i.e. it has
+ // been opened once by the NBT code itself so the node will
+ // answer Nodestatus requests to the name, but no client
+ // has opened it yet
+ //
+ if (pAddrElement->ClientHead.Flink->Flink == &pAddrElement->ClientHead)
+ {
+ status = STATUS_SUCCESS;
+ }
+ }
+ else
+ if ((pNameAddr->NameTypeState & STATE_CONFLICT))
+ {
+ // check if the name is in the process of being deregisterd -
+ // STATE_CONFLICT - in this case allow it to carry on and take over
+ // name.
+ //
+ status = STATUS_SUCCESS;
+ }
+
+ }
+
+ //
+ // check for a sharing failure, if so , then return
+ //
+ if (!NT_SUCCESS(status))
+ {
+
+ CHECK_PTR(pRequest);
+ pRequest->Handle.AddressHandle = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ NbtDereferenceAddress(pAddrElement);
+ status = STATUS_SHARING_VIOLATION;
+ goto ExitRoutine;
+
+ }
+
+
+ if (pNameAddr->NameTypeState & STATE_CONFLICT)
+ {
+ // this could either be a real conflict or a name being deleted on
+ // the net, so stop any timer associated with the name release
+ // and carry on
+ //
+ if (pTimer = pNameAddr->pTimer)
+ {
+ // this routine puts the timer block back on the timer Q, and
+ // handles race conditions to cancel the timer when the timer
+ // is expiring.
+ status = StopTimer(pTimer,&pClientCompletion,&Context);
+
+ // there is a client's irp waiting for the name release to finish
+ // so complete that irp back to them
+ if (pClientCompletion)
+ {
+
+ //
+ // NOTE****
+ // We must clear the AdapterMask so that NameReleaseDone
+ // does not try to release the name on another net card
+ // for the multihomed case.
+ //
+ CHECK_PTR(pNameAddr);
+ pNameAddr->AdapterMask = 0;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ (*pClientCompletion)(Context,STATUS_SUCCESS);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ }
+ CHECK_PTR(pNameAddr);
+ pNameAddr->pTimer = NULL;
+
+ }
+ //
+ // this allows another client to use a name almost immediately
+ // after the first one releases the name on the net. However
+ // if the first client has not released the name yet, and is
+ // still on the clienthead list, then the name will not be
+ // reregistered, and this current registration will fail because
+ // the name state is conflict. That check is done below.
+ //
+ if (IsListEmpty(&pAddrElement->ClientHead))
+ {
+ ReRegister = TRUE;
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= STATE_RESOLVING;
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Conflict State, re-registering name on net\n"));
+ }
+ else
+ {
+ // set status that indicates someone else has the name on the
+ // network.
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ NbtDereferenceAddress(pAddrElement);
+ status = STATUS_DUPLICATE_NAME;
+ goto ExitRoutine;
+ }
+
+ }
+ else
+ {
+ ReRegister = FALSE;
+
+ // name already exists - is open; allow only another client creating a
+ // name of the same type
+ //
+ if ((uAddrType == NBT_UNIQUE) || ( uAddrType == NBT_QUICK_UNIQUE))
+ {
+ if (!(pNameAddr->NameTypeState & NAMETYPE_UNIQUE))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ NbtDereferenceAddress(pAddrElement);
+ status = STATUS_SHARING_VIOLATION;
+ goto ExitRoutine;
+ }
+ }
+ else
+ if (!(pNameAddr->NameTypeState & NAMETYPE_GROUP))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ NbtDereferenceAddress(pAddrElement);
+ status = STATUS_SHARING_VIOLATION;
+ goto ExitRoutine;
+ }
+ }
+
+ // lock the address element so that we can
+ // coordinate with the name registration response handling in NBtRegister
+ // Completion below.
+ //
+ CTESpinLock(pAddrElement,OldIrq1);
+
+ // create client block and link to addresslist
+ // pass back the client block address as a handle for future reference
+ // to the client
+ pClientEle = NbtAllocateClientBlock((tADDRESSELE *)pNameAddr->pAddressEle);
+ if (!pClientEle)
+ {
+ CTESpinFree(pAddrElement,OldIrq1);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ NbtDereferenceAddress(pAddrElement);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ExitRoutine;
+
+ }
+
+ // we need to track the Irp so that when the name registration
+ // completes, we can complete the Irp.
+ pClientEle->pIrp = pIrp;
+
+ // keep track of which adapter this name is registered against.
+ pClientEle->pDeviceContext = (PVOID)pContext;
+ pClientEle->AddressType = TdiAddressType;
+
+ pRequest->Handle.AddressHandle = (PVOID)pClientEle;
+
+ // fill in the context values passed back to the client. These must
+ // be done before the name is registered on the network because the
+ // registration can succeed (or fail) before this routine finishes).
+ // Since this routine can be called by NBT itself, there may not be an
+ // irp to fill in, so check first.
+ if (pIrp)
+ {
+#ifndef VXD
+ NTSetFileObjectContexts(
+ pClientEle->pIrp,(PVOID)pClientEle,
+ (PVOID)(NBT_ADDRESS_TYPE));
+#endif
+ }
+
+ if (!(pNameAddr->AdapterMask & pContext->AdapterNumber))
+ {
+ // turn on the adapter's bit in the adapter Mask and set the
+ // re-register flag so we register the name out the new
+ // adapter.
+ //
+ pNameAddr->AdapterMask |= pContext->AdapterNumber;
+
+ // only if the state is resolved do we set the reregister flag,
+ // since in the resolving state, the name will be tacked on the
+ // end of the current registration
+ //
+ if ( pNameAddr->NameTypeState & STATE_RESOLVED)
+ {
+ MultiHomedReRegister = TRUE;
+ }
+ else
+ {
+ MultiHomedReRegister = FALSE;
+ }
+ }
+ else
+ {
+ // the adapter bit is already on in the pAddressEle, so
+ // this must be another client registering the same name,
+ // therefore turn on the MultiClient boolean so that the DgramRcv
+ // code will know to activate its multiple client rcv code.
+ //
+ pAddrElement->MultiClients = TRUE;
+ MultiHomedReRegister = FALSE;
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt: Setting MultiClients True for name %16.16s<%X> pClient=%X\n",
+ pNameRslv,(UCHAR)pNameRslv[15],pClientEle));
+ }
+
+ //
+ // check the state of the entry in the table. If the state is
+ // resolved then complete the request now,otherwise we cannot complete
+ // this request yet... i.e. we return Pending.
+ //
+ if (((pNameAddr->NameTypeState & STATE_RESOLVED) &&
+ (!MultiHomedReRegister)))
+// (pContext->IpAddress == 0)) // No IP from DHCP yet
+ {
+ // basically we are all done now, so just return status success
+ // to the client
+ //
+ status = STATUS_SUCCESS;
+
+ CHECK_PTR(pClientEle);
+ pClientEle->pIrp = NULL;
+ CTESpinFree(pAddrElement,OldIrq1);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ pClientEle->WaitingForRegistration = FALSE;
+
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Not Resolved State,waiting for previous registration- state= %X, ReRegister %X %X\n",
+ pNameAddr->NameTypeState,ReRegister,MultiHomedReRegister));
+
+ // we need to track the Irp so that when the name registration
+ // completes, we can complete the Irp.
+ pClientEle->pIrp = pIrp;
+
+
+ CTESpinFree(pAddrElement,OldIrq1);
+ if (MultiHomedReRegister || ReRegister)
+ {
+
+ // this flag is used by RegisterCompletion ( when true )
+ pClientEle->WaitingForRegistration = FALSE;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Resolved State,But Register state= %X, ReRegister %X %X\n",
+ pNameAddr->NameTypeState,ReRegister,MultiHomedReRegister));
+
+
+ // we need to re-register the name on the net because it is not
+ // currently in the resolved state and there is no timer active
+ // We do that by calling this routine with the IpAddress set to NULL
+ // to signal that routine not to put the name in the hash table
+ // since it is already there.
+ //
+ status = NbtRegisterName(
+ NBT_LOCAL,
+ 0, // set to zero to signify already in tbl
+ pNameRslv,
+ NbtConfig.pScope,
+ (PVOID)pClientEle,
+ (PVOID)NbtRegisterCompletion,
+ uAddrType,
+ pContext);
+
+ if (!NT_SUCCESS(status))
+ {
+ NbtDereferenceAddress(pAddrElement);
+ }
+ }
+ else
+ {
+ pClientEle->WaitingForRegistration = TRUE;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // for multihomed, a second registration on a second adapter
+ // at the same time as the first adapter is registering is
+ // delayed until the first completes, then its registration
+ // proceeds - See RegistrationCompletion below.
+ //
+ status = STATUS_PENDING;
+ }
+ }
+ }
+
+ExitRoutine:
+
+ CTEExReleaseResource(&NbtConfig.Resource);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtRegisterCompletion(
+ IN tCLIENTELE *pClientEleIn,
+ IN NTSTATUS status)
+
+/*++
+
+Routine Description
+
+ This routine handles completing a name registration request. The namesrv.c
+ Name server calls this routine when it has registered a name. The address
+ of this routine is passed to the Local Name Server in the NbtRegisterName
+ request.
+
+ The idea is to complete the irps that are waiting on the name registration,
+ one per client element.
+
+ When a DHCP reregister occurs there is no client irp so the name is
+ not actually deleted from the table when a bad status is passed to this
+ routine. Hence the need for the DhcpRegister flag to change the code
+ path for that case.
+
+Arguments:
+
+
+Return Values:
+
+ NTSTATUS - status of the request
+
+--*/
+{
+ LIST_ENTRY *pHead;
+ LIST_ENTRY *pEntry;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ tADDRESSELE *pAddress;
+ tDEVICECONTEXT *pDeviceContext;
+ tNAMEADDR *pNameAddr;
+ tCLIENTELE *pClientEle;
+ LIST_ENTRY TempList;
+ ULONG Count=0;
+
+ InitializeListHead(&TempList);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ pAddress = pClientEleIn->pAddress;
+ pDeviceContext = pClientEleIn->pDeviceContext;
+
+ CTESpinLock(pAddress,OldIrq);
+
+ // Several Clients can open the same address at the same time, so when the
+ // name registration completes, it should complete all of them!!
+
+
+ // increment the reference count so that the hash table entry cannot
+ // disappear while we are using it.
+ //
+ pAddress->RefCount++;
+ pNameAddr = pAddress->pNameAddr;
+
+
+ // if the registration failed or a previous registration failed for the
+ // multihomed case, deny the client the name
+ //
+ if (status != STATUS_SUCCESS)
+ {
+
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= STATE_CONFLICT;
+ status = STATUS_DUPLICATE_NAME;
+
+ }
+ else
+ {
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= STATE_RESOLVED;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // find all clients that are attached to the address and complete the
+ // I/O requests, if they are on the same adapter that the name was
+ // just registered against, if successful. For failure cases complete
+ // all irps with the failure code - i.e. failure to register a name on
+ // one adapter fails all adapters.
+ //
+FailRegistration:
+ pHead = &pAddress->ClientHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ // complete the I/O
+ pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
+
+ pEntry = pEntry->Flink;
+
+ //
+ // It is possible for the second registration of a name to fail so
+ // we do not want to attempt to return the irp on the first
+ // registration, which has completed ok already. Therefore
+ // if the status is failure, then only complete those clients that
+ // have the WaitingForReg... bit set
+ //
+ // if it is the client ele passed in, or one on the same device context
+ // that is waiting for a name registration, or it is a failure...
+ // AND the client IRP is still valid then return the Irp.
+ //
+ if (pClientEle->pIrp &&
+ ((pClientEle == pClientEleIn) ||
+ ((pClientEle->pDeviceContext == pDeviceContext) &&
+ pClientEle->WaitingForRegistration)
+ ||
+ ((status != STATUS_SUCCESS) && pClientEle->WaitingForRegistration)))
+ {
+ // for failed registrations, remove the client from the address list
+ // since we are going to delete him below.
+ if (!NT_SUCCESS(status))
+ {
+ // turn off the adapter bit so we know not to use this name with this
+ // adapter - since it is a failure, turn off all adapter bits
+ // since a single name registration failure means all registrations
+ // fail.
+ CHECK_PTR(pNameAddr);
+ pNameAddr->AdapterMask = 0;
+
+ // setting this to null prevents CloseAddress and CleanupAddress
+ // from accessing pAddress and crashing.
+ //
+ CHECK_PTR(pClientEle);
+ pClientEle->pAddress = NULL;
+
+ // clear the ptr to the ClientEle that NbtRegisterName put into
+ // the irp ( i.e. the context values are cleared )
+ //
+#ifndef VXD
+ NTSetFileObjectContexts(pClientEle->pIrp,NULL,NULL);
+
+#endif
+ RemoveEntryList(&pClientEle->Linkage);
+ }
+
+ ASSERT(pClientEle->pIrp);
+
+ pClientEle->WaitingForRegistration = FALSE;
+
+#ifndef VXD
+ // put all irps that have to be completed on a separate list
+ // and then complete later after releaseing the spin lock.
+ //
+ InsertTailList(&TempList,&pClientEle->pIrp->Tail.Overlay.ListEntry);
+#else
+ //
+ // pAddress gets set in the name table for this NCB
+ //
+ Count++;
+ CTESpinFree(pAddress,OldIrq1);
+ CTEIoComplete( pClientEle->pIrp, status, (ULONG) pClientEle ) ;
+ CTESpinLock(pAddress,OldIrq1);
+
+
+#endif
+ CHECK_PTR(pClientEle);
+ pClientEle->pIrp = NULL ;
+
+ // free the client object memory
+ if (!NT_SUCCESS(status))
+ {
+ NbtFreeClientObj(pClientEle);
+ }
+ }
+
+ }
+
+ CTESpinFree(pAddress,OldIrq1);
+
+#ifndef VXD
+ //
+ // for the NT case where MP - ness can disrupt the list at any
+ // time, scan the whole list above without releasing the spin lock,
+ // and then complete the irps collected here
+ //
+ while (!IsListEmpty(&TempList))
+ {
+ PIRP pIrp;
+
+ pEntry = RemoveHeadList(&TempList);
+ pIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
+
+ CTEIoComplete(pIrp,status,0);
+ Count++;
+ }
+#endif
+
+
+ // if the registration failed, do one more dereference of the address
+ // to remove the refcount added by this client. This may cause a name
+ // release on the network if there are no other clients registering
+ // the name.
+ //
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // dereference the address the same number of times that we have
+ // returned failed registrations since each reg. referenced pAddress
+ // once
+ //
+ while (Count--)
+ {
+ NbtDereferenceAddress(pAddress);
+ }
+ }
+ else
+ {
+ USHORT uAddrType;
+
+ CTESpinLock(pAddress,OldIrq1);
+
+ // go through the clients and see if any are waiting to register
+ // a name. This happens in the multihomed case, but should not
+ // happen in the single adapter case.
+ //
+ pHead = &pAddress->ClientHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ // complete the I/O
+ pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
+
+ pEntry = pEntry->Flink;
+
+ if (pClientEle->WaitingForRegistration)
+ {
+ ULONG SaveState;
+
+ pClientEle->WaitingForRegistration = FALSE;
+
+ if (pNameAddr->NameTypeState & NAMETYPE_UNIQUE)
+ {
+ uAddrType = NBT_UNIQUE;
+ }
+ else
+ uAddrType = NBT_GROUP;
+
+ //
+ // preserve the "QUICK"ness
+ //
+ if ( pNameAddr->NameTypeState & NAMETYPE_QUICK)
+ uAddrType |= NBT_QUICK_UNIQUE;
+
+ // should be multihomed to get to here!!
+ ASSERT(NbtConfig.MultiHomed);
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Registering next name state= %X,%15s<%X>\n",
+ pNameAddr->NameTypeState,pNameAddr->Name,pNameAddr->Name[15]));
+
+ SaveState = pNameAddr->NameTypeState;
+
+ CTESpinFree(pAddress,OldIrq1);
+
+ // this may be a multihomed host, with another name registration
+ // pending out another adapter, so start that registration.
+ status = NbtRegisterName(
+ NBT_LOCAL,
+ 0, // set to zero to signify already in tbl
+ pNameAddr->Name,
+ NbtConfig.pScope,
+ (PVOID)pClientEle,
+ (PVOID)NbtRegisterCompletion,
+ uAddrType,
+ pClientEle->pDeviceContext);
+
+ CTESpinLock(pAddress,OldIrq1);
+
+ // since nbtregister will set the state to Resolving, when
+ // it might be resolved already on one adapter.
+ pNameAddr->NameTypeState = SaveState;
+ if (!NT_SUCCESS(status))
+ {
+ // if this fails for some reason, then fail any other name
+ // registrations pending. - the registername call should not
+ // fail unless we are out of resources.
+ pClientEle->WaitingForRegistration = TRUE;
+ goto FailRegistration;
+ }
+ // just register one name at a time, unless we get immediate success
+ else if (status == STATUS_PENDING)
+ {
+ break;
+ }
+ else // SUCCESS
+ {
+ CTESpinFree(pAddress,OldIrq1);
+ CTEIoComplete(pClientEle->pIrp,status,0);
+ pClientEle->pIrp = NULL;
+ CTESpinLock(pAddress,OldIrq1);
+ }
+ }
+ }
+ CTESpinFree(pAddress,OldIrq1);
+
+ }
+
+ // this decrements for the RefCount++ done in this routine.
+ NbtDereferenceAddress(pAddress);
+
+ return(STATUS_SUCCESS);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtOpenConnection(
+ IN TDI_REQUEST *pRequest,
+ IN CONNECTION_CONTEXT ConnectionContext,
+ IN tDEVICECONTEXT *pDeviceContext)
+/*++
+
+Routine Description
+
+ This routine handles creating a connection object for the client. It
+ passes back a ptr to the connection so that OS specific portions of the
+ data structure can be filled in.
+
+Arguments:
+
+
+Return Values:
+
+ pConnectEle - ptr to the allocated connection data structure
+ TDI_STATUS - status of the request
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS ;
+ tCONNECTELE *pConnEle;
+ tLOWERCONNECTION *pLowerConn;
+
+ CTEPagedCode();
+
+ pConnEle = (tCONNECTELE *)NbtAllocMem(sizeof(tCONNECTELE),NBT_TAG('D'));
+ if (!pConnEle)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // Acquire this resource to co-ordinate with DHCP changing the IP
+ // address
+ CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:OpenConnection <%X>\n",pConnEle));
+
+ // This ensures that all BOOLEAN values begin with a FALSE value among other things.
+ CTEZeroMemory(pConnEle,sizeof(tCONNECTELE));
+
+ CTEInitLock(&pConnEle->SpinLock);
+
+ // initialize lists to empty
+ InitializeListHead(&pConnEle->Active);
+ InitializeListHead(&pConnEle->RcvHead);
+
+ // store a context value to return to the client in various
+ // Event calls(such as Receive or Disconnect events)
+ pConnEle->ConnectContext = ConnectionContext;
+
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ pConnEle->pDeviceContext = pDeviceContext;
+#endif
+
+ pConnEle->state = NBT_IDLE;
+ pConnEle->Verify = NBT_VERIFY_CONNECTION;
+ pConnEle->RefCount = 1; // so we don't delete the connection
+ pConnEle->LockNumber = CONNECT_LOCK;
+
+ // return the pointer to the block to the client as the connection
+ // id
+ pRequest->Handle.ConnectionContext = (PVOID)pConnEle;
+
+ // link on to list of open connections for this device so that we
+ // know how many open connections there are at any time (if we need to know)
+ // This linkage is only in place until the client does an associate, then
+ // the connection is unlinked from here and linked to the client ConnectHead.
+ //
+ ASSERT(pConnEle->RefCount == 1);
+ ExInterlockedInsertHeadList(&pDeviceContext->UpConnectionInUse,
+ &pConnEle->Linkage,
+ &pDeviceContext->SpinLock);
+ //
+ // for each connection the client(s) open, open a connection to the transport
+ // so that we can accept one to one from the transport.
+
+ // allocate an MDL to be used for partial Mdls
+ //
+#ifndef VXD
+ status = AllocateMdl(pConnEle);
+ if (NT_SUCCESS(status))
+#endif
+ {
+ if (pDeviceContext->pSessionFileObject)
+ {
+ //
+ // allocate memory for the lower connection block.
+ //
+ pLowerConn = (tLOWERCONNECTION *)NbtAllocMem(sizeof(tLOWERCONNECTION),NBT_TAG('E'));
+
+ if (pLowerConn)
+ {
+ status = NbtOpenAndAssocConnection(pLowerConn,pDeviceContext);
+ CHECK_PTR(pLowerConn);
+ pLowerConn->pIrp = NULL ;
+
+ if (NT_SUCCESS(status))
+ {
+ CTEExReleaseResource(&NbtConfig.Resource);
+ return(STATUS_SUCCESS);
+ }
+
+ CTEMemFree(pLowerConn);
+
+ }
+ else
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES ;
+ }
+
+#ifndef VXD
+ IoFreeMdl(pConnEle->pNewMdl);
+#endif
+ }
+ else
+ { //
+ // fake out the lower connection being openned when we are not yet
+ // bound to the transport
+ //
+ CTEExReleaseResource(&NbtConfig.Resource);
+ return(STATUS_SUCCESS);
+ }
+ }
+
+
+ // remove the pConnEle from the list
+ //
+ LockedRemoveFromList(pConnEle,pDeviceContext);
+
+ FreeConnectionObj(pConnEle);
+
+ CTEExReleaseResource(&NbtConfig.Resource);
+
+ return(status);
+}
+//----------------------------------------------------------------------------
+ VOID
+LockedRemoveFromList(
+ IN tCONNECTELE *pConnEle,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+
+/*++
+Routine Description:
+
+ This Routine handles removing pConnele from the list with the spin lock
+ held.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+
+ // remove the pConnEle from the list
+ //
+ CTESpinLock(pDeviceContext,OldIrq);
+ RemoveEntryList(&pConnEle->Linkage);
+ CTESpinFree(pDeviceContext,OldIrq);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtOpenAndAssocConnection(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+
+/*++
+Routine Description:
+
+ This Routine handles associating a Net Bios name with an open connection.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ NTSTATUS Locstatus;
+ BOOLEAN Attached=FALSE;
+
+ CTEPagedCode();
+
+ CTEAttachFsp(&Attached);
+
+ status = NbtTdiOpenConnection(pLowerConn,pDeviceContext);
+
+ // set this to null to signify that this lower connection does not
+ // have an address object associated with it specifically - i.e.
+ // it is an inbound connection associated with the 139 address, not
+ // an outbound connection associated with its own address.
+ //
+ CHECK_PTR(pLowerConn);
+ pLowerConn->pAddrFileObject = NULL;
+
+ if (NT_SUCCESS(status))
+ {
+ // now associate the connection with the 139 session address
+ status = NbtTdiAssociateConnection(
+ pLowerConn->pFileObject,
+#ifndef VXD
+ pDeviceContext->hSession);
+#else
+ // Address handle stored in pFileObjects as a VXD
+ (HANDLE) pDeviceContext->pSessionFileObject);
+#endif
+
+ if (!NT_SUCCESS(status))
+ {
+
+ KdPrint(("Nbt:Unable to associate a connection with the session address status = %X\n",
+ status));
+
+ NTDereferenceObject((PVOID *)pLowerConn->pFileObject);
+ Locstatus = NbtTdiCloseConnection(pLowerConn);
+ }
+ else
+ {
+ ASSERT(pLowerConn->RefCount == 1);
+ // insert on the connection free queue
+ ExInterlockedInsertHeadList(&pDeviceContext->LowerConnFreeHead,
+ &pLowerConn->Linkage,
+ &pDeviceContext->SpinLock);
+ }
+ }
+ else
+ {
+ KdPrint(("Nbt:Unable to open a connection with the session address status = %X\n",
+ status));
+
+ }
+
+ CTEDetachFsp(Attached);
+
+ return(status);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtAssociateAddress(
+ IN TDI_REQUEST *pRequest,
+ IN tCLIENTELE *pClientHandle,
+ IN PVOID pIrp
+ )
+
+/*++
+Routine Description:
+
+ This Routine handles associating a Net Bios name with an open connection.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ tCONNECTELE *pConnEle;
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ CTELockHandle OldIrq2;
+
+ pConnEle = pRequest->Handle.ConnectionContext;
+
+ // Need code here to check if the address has been registered on the net
+ // yet and if not, then this could must wait till then , then to the
+ // associate *TODO*
+
+ // check the connection element for validity
+ CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status)
+
+ // check the client element for validity now!
+ CTEVerifyHandle(pClientHandle,NBT_VERIFY_CLIENT,tCLIENTELE,&status)
+
+ CTESpinLock(pClientHandle->pDeviceContext,OldIrq2);
+ CTESpinLock(pConnEle,OldIrq1);
+ CTESpinLock(pClientHandle,OldIrq);
+
+ if (pConnEle->state != NBT_IDLE)
+ {
+ // the connection is in use, so reject the associate attempt
+ CTESpinFree(pClientHandle,OldIrq);
+ CTESpinFree(pConnEle,OldIrq1);
+ CTESpinFree(pClientHandle->pDeviceContext,OldIrq2);
+ return(STATUS_INVALID_HANDLE);
+ }
+ else
+ {
+ pConnEle->state = NBT_ASSOCIATED;
+ // link the connection to the client so we can find the client, given
+ // the connection.
+ pConnEle->pClientEle = (PVOID)pClientHandle;
+ }
+
+ // there can be multiple connections hooked to each client block - i.e.
+ // multiple connections per address per client. This allows the client
+ // to find its connections.
+ //
+ // first unlink from the device context UpconnectionsInUse, which was linked
+ // when the connection was created.
+ RemoveEntryList(&pConnEle->Linkage);
+
+ InsertTailList(&pClientHandle->ConnectHead,&pConnEle->Linkage);
+
+ CTESpinFree(pClientHandle,OldIrq);
+ CTESpinFree(pConnEle,OldIrq1);
+
+ CTESpinFree(pClientHandle->pDeviceContext,OldIrq2);
+
+ return(STATUS_SUCCESS);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtDisassociateAddress(
+ IN TDI_REQUEST *pRequest
+ )
+
+/*++
+Routine Description:
+
+ This Routine handles disassociating a Net Bios name with an open connection.
+ The expectation is that the
+ client will follow with a NtClose which will do the work in Cleanup and
+ Close Connection. Since not all clients call this it is duplicate work
+ to put some code here to. The Rdr always calls NtClose after calling
+ this.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ tCONNECTELE *pConnEle;
+ tCLIENTELE *pClientEle;
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ tDEVICECONTEXT *pDeviceContext;
+ TDI_REQUEST Request;
+ ULONG Flags;
+
+ pConnEle = pRequest->Handle.ConnectionContext;
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Dissassociate address, state = %X\n",pConnEle->state));
+
+ // check the connection element for validity
+ CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status)
+
+ CHECK_PTR(pConnEle);
+
+ pClientEle = pConnEle->pClientEle;
+
+ Flags = TDI_DISCONNECT_RELEASE;
+ switch (pConnEle->state)
+ {
+
+ case NBT_CONNECTING:
+ case NBT_RECONNECTING:
+ case NBT_SESSION_OUTBOUND:
+ case NBT_SESSION_WAITACCEPT:
+ case NBT_SESSION_INBOUND:
+ // do abortive disconnects when the session is not up yet
+ // to be sure the disconnect completes the client's irp.
+ Flags = TDI_DISCONNECT_ABORT;
+ case NBT_SESSION_UP:
+
+
+ //
+ // Call NbtDisconnect incase the connection has not disconnected yet
+ //
+ Request.Handle.ConnectionContext = (PVOID)pConnEle;
+
+ // call the non-NT specific function to disconnect the connection
+ //
+ status = NbtDisconnect(
+ &Request,
+ &DefaultDisconnectTimeout,
+ Flags,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ //
+ // NOTE: there is no BREAK here... the next case MUST be executed
+ // too.
+ //
+ case NBT_ASSOCIATED:
+ case NBT_DISCONNECTING:
+ case NBT_DISCONNECTED:
+ //
+ // remove the connection from the client and put back on the
+ // unassociated list
+ //
+ pDeviceContext = pClientEle->pDeviceContext;
+ CTESpinLock(pClientEle,OldIrq1);
+
+ if (pClientEle)
+ {
+ PLIST_ENTRY pHead,pEntry;
+ tLISTENREQUESTS *pListen;
+
+ pHead = &pClientEle->ListenHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pListen = CONTAINING_RECORD(pEntry,tLISTENREQUESTS,Linkage);
+ pEntry = pEntry->Flink; // Don't reference freed memory
+
+ if (pListen->pConnectEle == pConnEle)
+ {
+ RemoveEntryList(&pListen->Linkage);
+
+ CTESpinFree(pClientEle,OldIrq1);
+
+ CTEIoComplete( pListen->pIrp,STATUS_CANCELLED,0);
+
+ CTESpinLock(pClientEle,OldIrq1);
+
+ CTEMemFree((PVOID)pListen);
+ }
+ }
+ }
+
+ RemoveEntryList(&pConnEle->Linkage);
+ InitializeListHead(&pConnEle->Linkage);
+ CHECK_PTR(pConnEle);
+ CTESpinFree(pClientEle,OldIrq1);
+
+ CTESpinLock(pConnEle,OldIrq);
+ CTESpinLock(pClientEle,OldIrq1);
+ RemoveEntryList(&pConnEle->Linkage);
+ pConnEle->state = NBT_IDLE;
+ pConnEle->pClientEle = NULL;
+ pConnEle->DiscFlag = 0;
+ CTESpinFree(pClientEle,OldIrq1);
+ CTESpinFree(pConnEle,OldIrq);
+
+
+ ExInterlockedInsertTailList(&pDeviceContext->UpConnectionInUse,
+ &pConnEle->Linkage,
+ &pDeviceContext->SpinLock);
+
+ break;
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtCloseAddress(
+ IN TDI_REQUEST *pRequest,
+ OUT TDI_REQUEST_STATUS *pRequestStatus,
+ IN tDEVICECONTEXT *pContext,
+ IN PVOID pIrp)
+
+/*++
+
+Routine Description
+
+ This routine closes an address object for the client. Any connections
+ associated with the address object are immediately aborted and any requests
+ pending on the connection associated with the address object are
+ immediately completed with an appropriate error code. Any event handlers
+ that are registered are immediately deregistered and will not be called
+ after this request completes.
+
+ Note the the client actually passes a handle to the client object which is
+ chained off the address object. It is the client object that is closed,
+ which represents this clients attachment to the address object. Other
+ clients can continue to use the address object.
+
+Arguments:
+ pRequest->Handle.AddressHandle - ptr to the ClientEle object.
+ pRequestStatus - return status for asynchronous completions.
+ pContext - the NBT device that this address is valid upon
+ pIrp - ptr to track for NT compatibility.
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ tCLIENTELE *pClientEle;
+ NTSTATUS status;
+#ifndef VXD
+ UCHAR IrpFlags;
+ PIO_STACK_LOCATION pIrpsp;
+#endif
+
+ pClientEle = (tCLIENTELE *)pRequest->Handle.ConnectionContext;
+ if (!pClientEle->pAddress)
+ {
+ // the address has already been deleted.
+ return(STATUS_SUCCESS);
+ }
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Close Address Hit %16.16s<%X> %X\n",
+ pClientEle->pAddress->pNameAddr->Name,
+ pClientEle->pAddress->pNameAddr->Name[15],pClientEle));
+
+#ifdef VXD
+ CTEVerifyHandle(pClientEle,NBT_VERIFY_CLIENT,tCLIENTELE,&status);
+
+ //
+ // In NT-Land, closing connections is a two stage affair. However in
+ // the Vxd-Land, it is just a close, so call the other cleanup function
+ // here to do most of the work. In the NT implementation it is called
+ // from Ntisol.c, NTCleanupAddress.
+ //
+ pClientEle->pIrp = pIrp ;
+ status = NbtCleanUpAddress(pClientEle,pClientEle->pDeviceContext);
+#else
+ // Note the special verifier that is set during the cleanup phase.
+ CTEVerifyHandle(pClientEle,NBT_VERIFY_CLIENT_DOWN,tCLIENTELE,&status);
+
+ //
+ // clear the context value in the FileObject so that the client cannot
+ // pass this to us again
+ //
+ (VOID)NTClearFileObjectContext(pIrp);
+ pClientEle->pIrp = pIrp;
+
+ pIrpsp = IoGetCurrentIrpStackLocation(((PIRP)pIrp));
+
+ IrpFlags = pIrpsp->Control;
+ IoMarkIrpPending(((PIRP)pIrp));
+
+#endif
+
+ status = NbtDereferenceClient(pClientEle);
+
+#ifndef VXD
+ if (status != STATUS_PENDING)
+ {
+ pIrpsp->Control = IrpFlags;
+ }
+
+#endif
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtCleanUpAddress(
+ IN tCLIENTELE *pClientEle,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+
+/*++
+Routine Description:
+
+ This Routine handles the first stage of releasing an address object.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnEle;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq2;
+ CTELockHandle OldIrq3;
+ PLIST_ENTRY pHead,pEntry;
+ PLIST_ENTRY pEntryConn;
+ tADDRESSELE *pAddress;
+ DWORD dwNumConn=0;
+ DWORD i;
+
+ // to prevent connections and datagram from the wire...remove from the
+ // list of clients hooked to the address element
+ //
+ pAddress = pClientEle->pAddress;
+ if (!pAddress)
+ {
+ // the address has already been deleted.
+ return(STATUS_SUCCESS);
+ }
+
+ // lock the address to coordinate with receiving datagrams - to avoid
+ // allowing the client to free datagram receive buffers in the middle
+ // of DgramHndlrNotOs finding a buffer
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq3);
+
+ if (!IsListEmpty(&pClientEle->RcvDgramHead))
+ {
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tRCVELE *pRcvEle;
+ PCTE_IRP pRcvIrp;
+
+ pHead = &pClientEle->RcvDgramHead;
+ pEntry = pHead->Flink;
+
+ // prevent any datagram from the wire seeing this list
+ //
+ InitializeListHead(&pClientEle->RcvDgramHead);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq3);
+
+ while (pEntry != pHead)
+ {
+ pRcvEle = CONTAINING_RECORD(pEntry,tRCVELE,Linkage);
+ pRcvIrp = pRcvEle->pIrp;
+
+ CTEIoComplete(pRcvIrp,STATUS_NETWORK_NAME_DELETED,0);
+
+ pEntry = pEntry->Flink;
+
+ CTEMemFree(pRcvEle);
+ }
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq3);
+
+ // lock the client and the device context till we're done
+ CTESpinLock(pClientEle,OldIrq);
+
+#ifndef VXD
+ //
+ // set to prevent reception of datagrams
+ // (Vxd doesn't use this handler)
+ //
+ pClientEle->evRcvDgram = TdiDefaultRcvDatagramHandler;
+#endif
+
+ // so no one else can access the client element, set state to down. Therefore
+ // the verify checks will fail anywhere the client is accessed in the code,
+ // except in the NbtCloseAddress code which checks for this verifier value.
+ //
+ pClientEle->Verify = NBT_VERIFY_CLIENT_DOWN;
+
+ //
+ // Disassociate all Connections from this address object, first starting
+ // with any active connections, then followup with any idle connections.
+ //
+ pDeviceContext = pClientEle->pDeviceContext;
+ while ( !IsListEmpty( &pClientEle->ConnectActive ))
+ {
+ pEntry = RemoveHeadList( &pClientEle->ConnectActive ) ;
+
+ InitializeListHead(pEntry);
+ CTESpinFree(pClientEle,OldIrq);
+ pConnEle = CONTAINING_RECORD( pEntry, tCONNECTELE, Linkage ) ;
+
+//
+// if we had a connection in partial rcv state, make sure to remove it from
+// the list
+//
+#ifdef VXD
+ pLowerConn = pConnEle->pLowerConnId;
+
+ if ( pLowerConn->StateRcv == PARTIAL_RCV &&
+ (pLowerConn->fOnPartialRcvList == TRUE) )
+ {
+ RemoveEntryList( &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+ }
+#endif
+
+ status = NbtCleanUpConnection(pConnEle,pDeviceContext);
+
+
+ CTESpinLock(pConnEle,OldIrq);
+ CTESpinLock(pClientEle,OldIrq2);
+ //
+ // remove from this list again incase SessionSetupContinue has put it
+ // back on the list - if no one has put it back on this list this
+ // call is a no op since we initialized the list head above
+ //
+ RemoveEntryList(&pConnEle->Linkage);
+ pConnEle->state = NBT_IDLE;
+ CHECK_PTR(pConnEle);
+ pConnEle->pClientEle = NULL;
+ CTESpinFree(pClientEle,OldIrq2);
+ CTESpinFree(pConnEle,OldIrq);
+ PUSH_LOCATION(0x80);
+
+ //
+ // put on the idle connection list, to wait for a close connection
+ // to come down.
+ //
+ ASSERT(pConnEle->RefCount == 1);
+ ExInterlockedInsertTailList(&pDeviceContext->UpConnectionInUse,
+ &pConnEle->Linkage,
+ &pDeviceContext->SpinLock);
+ CTESpinLock(pClientEle,OldIrq);
+
+
+ }
+
+ //
+ // each idle connection creates a lower connection to the transport for
+ // inbound calls, therefore close a transport connection for each
+ // connection in this list and then "dissassociate" the connection from
+ // the address.
+ //
+ pHead = &pClientEle->ConnectHead;
+ pEntry = pHead->Flink;
+ //
+ // make the list look empty so no connections will be serviced inbound
+ // from the wire
+ //
+ InitializeListHead(pHead);
+ CTESpinFree(pClientEle,OldIrq);
+
+ CTESpinLock(pDeviceContext,OldIrq);
+ while (pEntry != pHead )
+ {
+
+ pConnEle = CONTAINING_RECORD(pEntry,tCONNECTELE,Linkage);
+
+ ASSERT ( ( pConnEle->Verify == NBT_VERIFY_CONNECTION ) || ( pConnEle->Verify == NBT_VERIFY_CONNECTION_DOWN ) );
+
+ pEntry = pEntry->Flink;
+
+ RemoveEntryList(&pConnEle->Linkage);
+
+ CTESpinLock(pConnEle,OldIrq2);
+
+ // disassociate the connection from the address by changing its state
+ // to idle and linking it to the pDeviceContext list of unassociated
+ // connections
+ //
+ pConnEle->state = NBT_IDLE;
+ CHECK_PTR(pConnEle);
+ pConnEle->Verify = NBT_VERIFY_CONNECTION_DOWN;
+ pConnEle->pClientEle = NULL;
+ ASSERT(pConnEle->RefCount == 1);
+ InsertTailList(&pDeviceContext->UpConnectionInUse,&pConnEle->Linkage);
+
+ CTESpinFree(pConnEle,OldIrq2);
+
+ //
+ // Count up the # of connections that were associated here so we can free that many lowerblocks
+ // later.
+ //
+ dwNumConn++;
+ }
+
+ for (i=0; i<dwNumConn; i++) {
+ //
+ // Get a free connection to the transport and close it
+ // for each free connection on this list. It is possible that this
+ // free list could be empty if an inbound connection was occurring
+ // right at this moment. In which case we would leave an extra connection
+ // object to the transport lying around... not a problem.
+ //
+ if (!IsListEmpty(&pDeviceContext->LowerConnFreeHead))
+ {
+ pEntryConn = RemoveHeadList(&pDeviceContext->LowerConnFreeHead);
+
+ pLowerConn = CONTAINING_RECORD(pEntryConn,tLOWERCONNECTION,Linkage);
+
+ CTESpinFree(pDeviceContext,OldIrq);
+
+#ifndef VXD
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Closing Handle %X -> %X\n",pLowerConn,pLowerConn->FileHandle));
+#else
+ KdPrint(("Nbt:Closing Handle %X -> %X\n",pLowerConn,pLowerConn->pFileObject));
+#endif
+ // dereference the fileobject ptr
+ //NTDereferenceObject((PVOID *)pLowerConn->pFileObject);
+ //status = NbtTdiCloseConnection(pLowerConn);
+
+ NbtDereferenceLowerConnection(pLowerConn);
+
+ CTESpinLock(pDeviceContext,OldIrq);
+ }
+ }
+ CTESpinFree(pDeviceContext,OldIrq);
+
+ // check for any datagrams still outstanding. These could be waiting on
+ // name queries to complete, so there could be timers associated with them
+ //
+
+
+ //
+ // Complete any outstanding listens not on an active connection
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq2);
+
+ CTESpinLock(pClientEle,OldIrq);
+
+ pHead = &pClientEle->ListenHead;
+ pEntry = pHead->Flink;
+ //
+ // make the list look empty so no connections will be serviced inbound
+ // from the wire
+ //
+ InitializeListHead(pHead);
+
+ CTESpinFree(pClientEle, OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+
+ while (pEntry != pHead )
+ {
+ tLISTENREQUESTS * pListen ;
+
+ pListen = CONTAINING_RECORD(pEntry,tLISTENREQUESTS,Linkage);
+ pEntry = pEntry->Flink;
+
+ CTEIoComplete( pListen->pIrp, STATUS_NETWORK_NAME_DELETED, 0);
+ CTEMemFree( pListen );
+ }
+
+#ifdef VXD
+ //
+ // Complete any outstanding ReceiveAnys on this client element
+ //
+ DbgPrint("NbtCleanupAddress: Completing all RcvAny NCBs\r\n") ;
+ CTESpinLock(&NbtConfig.JointLock,OldIrq2);
+
+ CTESpinLock(pClientEle,OldIrq);
+
+ pHead = &pClientEle->RcvAnyHead;
+ pEntry = pHead->Flink;
+ //
+ // make the list look empty so no connections will be serviced inbound
+ // from the wire
+ //
+ InitializeListHead(pHead);
+
+ CTESpinFree(pClientEle, OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+
+ while (pEntry != pHead )
+ {
+ PRCV_CONTEXT pRcvContext ;
+
+ pRcvContext = CONTAINING_RECORD(pEntry,RCV_CONTEXT,ListEntry);
+ pEntry = pEntry->Flink;
+
+ CTEIoComplete( pRcvContext->pNCB, STATUS_NETWORK_NAME_DELETED, TRUE );
+
+ FreeRcvContext( pRcvContext );
+ }
+#endif
+
+ // *TODO the code above only removes names that are being resolved, and
+ // leaves any datagram sends that are currently active with the
+ // transport... these should be cancelled too by cancelling the irp..
+ // Put this code in when the Irp cancelling code is done.
+
+ return(STATUS_SUCCESS);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtCloseConnection(
+ IN TDI_REQUEST *pRequest,
+ OUT TDI_REQUEST_STATUS *pRequestStatus,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pIrp)
+
+/*++
+
+Routine Description
+
+ This routine closes a connection object for the client. Closing is
+ different than disconnecting. A disconnect breaks a connection with a
+ peer whereas the close removes this connection endpoint from the local
+ NBT only. NtClose causes NTCleanup to be called first which does the
+ session close. This routine then does frees memory associated with the
+ connection elements.
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STTTUS - status of the request
+
+--*/
+{
+ tCONNECTELE *pConnEle;
+ NTSTATUS status;
+
+ pConnEle = pRequest->Handle.ConnectionContext;
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt: Close Connection Hit!! state = %X pConnEle %X\n",pConnEle->state,pConnEle));
+
+#ifndef VXD
+ CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION_DOWN,tCONNECTELE,&status);
+
+
+#else
+ CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status);
+ //
+ // Call the Cleanup function, which NT calls from ntisol, NtCleanupConnection
+ //
+ status = NbtCleanUpConnection(pConnEle,pDeviceContext );
+#endif
+
+ // NOTE:
+ // the NBtDereference routine will complete the irp and return pending
+ //
+ pConnEle->pIrpClose = pIrp;
+ status = NbtDereferenceConnection(pConnEle);
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtCleanUpConnection(
+ IN tCONNECTELE *pConnEle,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+Routine Description:
+
+ This Routine handles running down a connection in preparation for a close
+ that will come in next. NtClose hits this entry first, and then it hits
+ the NTCloseConnection next. If the connection was outbound, then the
+ address object must be closed as well as the connection. This routine
+ mainly deals with the pLowerconn connection to the transport whereas
+ NbtCloseConnection deals with closing pConnEle, the connection to the client.
+
+ If DisassociateConnection is called by the client then it will do most of
+ this cleanup.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ NTSTATUS Locstatus;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq2;
+ tLOWERCONNECTION *pLowerConn;
+ PLIST_ENTRY pEntry;
+ BOOLEAN Originator = TRUE;
+ ULONG LowerState = NBT_IDLE;
+ TDI_REQUEST Request;
+ tLISTENREQUESTS *pListen;
+ tCLIENTELE *pClientEle;
+ PLIST_ENTRY pHead;
+ BOOLEAN QueueCleanupBool=FALSE;
+ BOOLEAN DoDisconnect=TRUE;
+ BOOLEAN FreeLower;
+
+ //
+ // save the lower connection origination flag for later
+ //
+ pLowerConn = pConnEle->pLowerConnId;
+ if (pLowerConn)
+ {
+ Originator = pLowerConn->bOriginator;
+ }
+
+ // the connection has not been associated so there is no further work to
+ // do here.
+ //
+ CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
+ if (pConnEle->state == NBT_IDLE)
+ {
+ // The connection has already been disassociated, and
+ // the next action will be a close, so change the verifier to allow
+ // the close to complete
+ //
+ PUSH_LOCATION(0x81);
+ }
+ else
+ {
+ BOOLEAN DoCleanup = FALSE;
+
+ CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status);
+
+
+ //
+ // check if there is an outstanding name query going on and if so
+ // then cancel the timer and call the completion routine.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq2);
+ CTESpinLock(pConnEle,OldIrq);
+
+ if ((pConnEle->state == NBT_CONNECTING) ||
+ (pConnEle->state == NBT_RECONNECTING))
+ {
+ status = CleanupConnectingState(pConnEle,pDeviceContext,&OldIrq,&OldIrq2);
+ //
+ // Pending means that the connection is currently being setup
+ // by TCP, so do a disconnect, below.
+ //
+ if (status != STATUS_PENDING)
+ {
+ //
+ // Since the connection is not setup with the transport yet
+ // there is no need to call nbtdisconnect
+ //
+ DoDisconnect = FALSE;
+ }
+ }
+
+
+ //
+ // all other states of the connection are handled by NbtDisconnect
+ // which will send a disconnect down the to transport and then
+ // cleanup things.
+ //
+
+ CTESpinFree(pConnEle,OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+
+ CTEExReleaseResource(&NbtConfig.Resource);
+ Request.Handle.ConnectionContext = (PVOID)pConnEle;
+
+ if (DoDisconnect)
+ {
+ status = NbtDisconnect(
+ &Request,
+ &DefaultDisconnectTimeout,
+ TDI_DISCONNECT_ABORT,
+ NULL,
+ NULL,
+ NULL
+ );
+ }
+
+ CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
+
+ // we don't want to return Invalid connection if we disconnect an
+ // already disconnected connection.
+ if (status == STATUS_CONNECTION_INVALID)
+ {
+ status = STATUS_SUCCESS;
+ }
+ }
+
+ //
+ // if the verify value is already set to connection down then we have
+ // been through here already and do not want to free a lower connection.
+ // i.e. when the client calls close address then calls close connection.
+ //
+ if (pConnEle->Verify == NBT_VERIFY_CONNECTION)
+ {
+ FreeLower = TRUE;
+ }
+ else
+ FreeLower = FALSE;
+
+ pConnEle->Verify = NBT_VERIFY_CONNECTION_DOWN;
+
+
+ //
+ // Free any posted Rcv buffers that have not been filled
+ //
+
+ CTESpinLock(pConnEle,OldIrq);
+
+ FreeRcvBuffers(pConnEle,&OldIrq);
+
+ CTESpinFree(pConnEle,OldIrq);
+
+
+ // check if any listens have been setup for this connection, and
+ // remove them if so
+ //
+ pClientEle = pConnEle->pClientEle;
+
+ if (pClientEle)
+ {
+ CTESpinLock(pClientEle,OldIrq);
+
+ pHead = &pClientEle->ListenHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pListen = CONTAINING_RECORD(pEntry,tLISTENREQUESTS,Linkage);
+ pEntry = pEntry->Flink; // Don't reference freed memory
+
+ if (pListen->pConnectEle == pConnEle)
+ {
+ RemoveEntryList(&pListen->Linkage);
+
+ CTESpinFree(pClientEle,OldIrq);
+
+ CTEIoComplete( pListen->pIrp,STATUS_CANCELLED,0);
+
+ CTESpinLock(pClientEle,OldIrq);
+
+ CTEMemFree((PVOID)pListen);
+ }
+ }
+ CTESpinFree(pClientEle,OldIrq);
+ }
+
+ // For outbound connections the lower connection is deleted in hndlrs.c
+ // For inbound connections, the lower connection is put back on the free
+ // list in hndlrs.c and one from that list is deleted here. Therefore
+ // delete a lower connection in this list if the connection is inbound.
+ //
+ if ((!pConnEle->Orig) && FreeLower)
+ {
+ // get a lower connection from the free list and close it with the
+ // transport.
+ //
+ CTESpinLock(pDeviceContext,OldIrq);
+ if (!IsListEmpty(&pDeviceContext->LowerConnFreeHead))
+ {
+ pEntry = RemoveHeadList(&pDeviceContext->LowerConnFreeHead);
+ pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Closing Lower Conn %X\n",pLowerConn));
+
+ CTESpinFree(pDeviceContext,OldIrq);
+ // dereference the fileobject ptr
+ //NTDereferenceObject((PVOID *)pLowerConn->pFileObject);
+
+
+ // close the lower connection with the transport
+#ifndef VXD
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Closing Handle %X -> %X\n",pLowerConn,pLowerConn->FileHandle));
+#else
+ KdPrint(("Nbt:Closing Handle %X -> %X\n",pLowerConn,pLowerConn->pFileObject));
+#endif
+ //Locstatus = NbtTdiCloseConnection(pLowerConn);
+
+ NbtDereferenceLowerConnection(pLowerConn);
+ }
+ else
+ {
+ CTESpinFree(pDeviceContext,OldIrq);
+ }
+ }
+
+ //
+ // Unlink the connection element from the client's list or the device context
+ // if its not associated yet.
+ //
+ CTESpinLock(pDeviceContext,OldIrq);
+ if (pConnEle->state > NBT_IDLE)
+ {
+ CTESpinLock(pConnEle->pClientEle,OldIrq2);
+
+ RemoveEntryList(&pConnEle->Linkage);
+
+ CTESpinFree(pConnEle->pClientEle,OldIrq2);
+
+ // do the disassociate here
+ //
+ CTESpinLock(pConnEle,OldIrq2);
+ pConnEle->state = NBT_IDLE;
+ CHECK_PTR(pConnEle);
+ pConnEle->pClientEle = NULL;
+ CTESpinFree(pConnEle,OldIrq2);
+
+ }
+ else
+ {
+ RemoveEntryList(&pConnEle->Linkage);
+ }
+
+ InitializeListHead(&pConnEle->Linkage);
+
+ CTESpinFree(pDeviceContext,OldIrq);
+ CTEExReleaseResource(&NbtConfig.Resource);
+
+ // this could be status pending from NbtDisconnect...
+ //
+ return(status);
+}
+//----------------------------------------------------------------------------
+ VOID
+FreeRcvBuffers(
+ tCONNECTELE *pConnEle,
+ CTELockHandle *pOldIrq
+ )
+/*++
+Routine Description:
+
+ This Routine handles freeing any recv buffers posted by the client.
+ The pConnEle lock could be held prior to calling this routine.
+
+Arguments:
+
+ pListHead
+ pTracker
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PLIST_ENTRY pHead;
+
+ pHead = &pConnEle->RcvHead;
+ while (!IsListEmpty(pHead))
+ {
+ PLIST_ENTRY pRcvEntry;
+ PVOID pRcvElement ;
+
+ KdPrint(("***Nbt:Freeing Posted Rcvs on Connection Cleanup!\n"));
+ pRcvEntry = RemoveHeadList(pHead);
+ CTESpinFree(pConnEle,*pOldIrq);
+
+#ifndef VXD
+ pRcvElement = CONTAINING_RECORD(pRcvEntry,IRP,Tail.Overlay.ListEntry);
+ CTEIoComplete( (PIRP) pRcvElement, STATUS_CANCELLED,0);
+#else
+ pRcvElement = CONTAINING_RECORD(pRcvEntry, RCV_CONTEXT, ListEntry ) ;
+ CTEIoComplete( ((PRCV_CONTEXT)pRcvEntry)->pNCB, STATUS_CANCELLED, 0);
+#endif
+
+ CTESpinLock(pConnEle,*pOldIrq);
+ }
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+CheckListForTracker(
+ IN PLIST_ENTRY pListHead,
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ OUT NBT_WORK_ITEM_CONTEXT **pContextRet
+ )
+/*++
+Routine Description:
+
+ This Routine handles searching a list for a matching Tracker block.
+ The JointLock is held when calling this routine.
+
+Arguments:
+
+ pListHead
+ pTracker
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PLIST_ENTRY pEntry;
+ PLIST_ENTRY pHead;
+ NBT_WORK_ITEM_CONTEXT *Context;
+ ULONG Count;
+
+ //
+ // start by checking for LmHost Name queries
+ //
+ pHead = &LmHostQueries.ToResolve;
+
+ Count = 2;
+ while (Count--)
+ {
+ pEntry = pHead->Flink;
+
+ while (pEntry != pHead)
+ {
+ Context = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
+ if (pTracker == Context->pTracker)
+ {
+ RemoveEntryList(pEntry);
+ *pContextRet = Context;
+ return(STATUS_SUCCESS);
+ }
+ else
+ pEntry = pEntry->Flink;
+
+ }
+
+#ifndef VXD
+ //
+ // now check the DnsQueries List
+ //
+ if (Count)
+ {
+ pHead = &DnsQueries.ToResolve;
+ }
+#endif
+ }
+
+ return(STATUS_UNSUCCESSFUL);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+CleanupConnectingState(
+ IN tCONNECTELE *pConnEle,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN CTELockHandle *OldIrq, // pConnEle lock
+ IN CTELockHandle *OldIrq2 // joint lock
+ )
+/*++
+Routine Description:
+
+ This Routine handles running down a connection in the NBT_CONNECTING
+ state since that connection could be doing a number of things such as:
+ 1) Broadcast or WINS name Query
+ 2) LmHosts name query
+ 3) DNS name query
+ 4) Tcp Connection setup
+
+ The JointLock and the pConnEle lock are held when calling this routine.
+
+Arguments:
+
+ pConnEle - ptr to the connection
+ pDeviceContext - the device context
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tNAMEADDR *pNameAddr;
+ NBT_WORK_ITEM_CONTEXT *pWiContext = NULL;
+ tLOWERCONNECTION *pLowerConn;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+ NTSTATUS Locstatus;
+
+ //
+ // save the lower connection origination flag for later
+ //
+ pLowerConn = pConnEle->pLowerConnId;
+ //CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&Locstatus);
+
+ if (pConnEle->state == NBT_CONNECTING)
+ {
+ if (pLowerConn->State == NBT_CONNECTING)
+ {
+ LOCATION(0x6E)
+ //
+ // We are setting up the TCP connection to the transport Now
+ // so it is safe to call NbtDisconnect on this connection and
+ // let that cleanup the mess - use this retcode to signify that.
+ //
+ return(STATUS_PENDING);
+
+ }
+
+ //
+ // check if the name query is held up in doing a LmHost or DNS
+ // Name Query
+ //
+
+ // check if there is an outstanding name query going on and if so
+ // then cancel the timer and call the completion routine.
+ //
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Cleanup in the Connecting State %X\n",pConnEle));
+
+ if (pConnEle->pTracker)
+ {
+ LOCATION(0x6F)
+ // this is the QueryNameOnNet tracker, not the session setup
+ // tracker
+ //
+ pTracker = pConnEle->pTracker;
+
+ pNameAddr = NULL;
+ status = FindInHashTable(NbtConfig.pRemoteHashTbl,
+ pTracker->pNameAddr->Name,
+ NbtConfig.pScope,
+ &pNameAddr);
+
+ PUSH_LOCATION(0x82);
+ //
+ // if there is a timer, then the connection setup is still
+ // waiting on the name query. If no timer, then we could be
+ // waiting on an LmHosts or DNS name query or we
+ // are waiting on the TCP connection setup - stopping the timer
+ // should cleanup the tracker.
+ //
+ if (NT_SUCCESS(status))
+ {
+ tTIMERQENTRY *pTimer;
+ LOCATION(0x70);
+ if (pNameAddr->NameTypeState & STATE_RESOLVED)
+ {
+ //
+ // the name has resolved, but not started setting up the
+ // session yet, so return this status to tell the caller
+ // to cancel the tracker.
+ //
+ return(STATUS_UNSUCCESSFUL);
+ }
+ else
+ if (pTimer = pNameAddr->pTimer)
+ {
+ LOCATION(0x71);
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got Cleanup During Active NameQuery: pConnEle %X\n",
+ pConnEle));
+ CHECK_PTR(pNameAddr);
+
+ pNameAddr->pTimer = NULL;
+ status = StopTimer(pTimer,&pClientCompletion,&Context);
+
+ //
+ // remove the name from the hash table, since it did not resolve
+ //
+ pNameAddr->NameTypeState &= ~STATE_RESOLVING;
+ pNameAddr->NameTypeState |= STATE_RELEASED;
+ pNameAddr->pTracker = NULL;
+ if (pClientCompletion)
+ {
+ NbtDereferenceName(pNameAddr);
+ }
+
+ // since StopTimer should have cleaned up the tracker, null
+ // it out
+
+ pTracker = NULL;
+ }
+ else
+ {
+ NBT_WORK_ITEM_CONTEXT *WiContext;
+ LOCATION(0x72);
+ status = STATUS_UNSUCCESSFUL;
+
+ //
+ // check if the name is waiting on an LmHost name Query
+ // or a DNS name query
+ //
+ WiContext = ((NBT_WORK_ITEM_CONTEXT *)LmHostQueries.Context);
+ if (WiContext && (WiContext->pTracker == pTracker))
+ {
+ LOCATION(0x73);
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Found NameQuery on Lmhost Context: pConnEle %X\n",
+ pConnEle));
+ pWiContext = WiContext;
+ LmHostQueries.Context = NULL;
+ NTClearContextCancel( pWiContext );
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ LOCATION(0x74);
+ //
+ // check the list for this tracker
+ //
+ status = CheckListForTracker(&LmHostQueries.ToResolve,
+ pTracker,
+ &pWiContext);
+ if (NT_SUCCESS(status))
+ {
+ LOCATION(0x75);
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Found NameQuery on Lmhost Q: pConnEle %X\n",
+ pConnEle));
+
+ }
+#ifndef VXD
+ else
+ if (((NBT_WORK_ITEM_CONTEXT *)DnsQueries.Context) &&
+ ((NBT_WORK_ITEM_CONTEXT *)DnsQueries.Context)->pTracker == pTracker)
+ {
+ LOCATION(0x76);
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Found NameQuery on Dns Context: pConnEle %X\n",
+ pConnEle));
+
+ pWiContext = DnsQueries.Context;
+ DnsQueries.Context = NULL;
+ NTClearContextCancel( pWiContext );
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ LOCATION(0x78);
+ //
+ // check the list for this tracker
+ //
+ status = CheckListForTracker(&DnsQueries.ToResolve,
+ pTracker,
+ &pWiContext);
+ if (NT_SUCCESS(status))
+ {
+ LOCATION(0x79);
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Found NameQuery on Dns Q: pConnEle %X\n",
+ pConnEle));
+
+ }
+ }
+#endif
+ }
+ }
+
+ }
+
+ // ...else....
+ // the completion routine has already run, so we are
+ // in the state of starting a Tcp Connection, so
+ // let nbtdisconnect handle it. (below).
+ //
+ }
+ } // connnecting state
+ else
+ if (pConnEle->state == NBT_RECONNECTING)
+ {
+ LOCATION(0x77);
+ //
+ // this should signal NbtConnect not to do the reconnect
+ //
+ pConnEle->pTracker->Flags = TRACKER_CANCELLED;
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ // for items on the LmHost or Dns queues, get the completion routine
+ // out of the Work Item context first
+ //
+ if (pWiContext)
+ {
+ LOCATION(0x78);
+ pClientCompletion = pWiContext->ClientCompletion;
+ Context = pWiContext->pClientContext;
+
+ // for DNS and LmHosts, the tracker needs to be freed and the name
+ // removed from the hash table
+ //
+ if (pTracker)
+ {
+
+ LOCATION(0x79);
+ CTESpinFree(pConnEle,*OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,*OldIrq2);
+ //
+ // remove the name from the hash table, since it did not resolve
+ //
+ RemoveName(pTracker->pNameAddr);
+
+ DereferenceTracker(pTracker);
+
+ CTESpinLock(&NbtConfig.JointLock,*OldIrq2);
+ CTESpinLock(pConnEle,*OldIrq);
+ }
+
+ CTEMemFree(pWiContext);
+ }
+
+ if (pClientCompletion)
+ {
+ LOCATION(0x7A);
+ CTESpinFree(pConnEle,*OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,*OldIrq2);
+
+ //
+ // The completion routine is SessionSetupContinue
+ // and it will cleanup the lower connection and
+ // return the client's irp
+ //
+
+ status = STATUS_SUCCESS;
+ CompleteClientReq(pClientCompletion,
+ Context,STATUS_CANCELLED);
+
+
+ CTESpinLock(&NbtConfig.JointLock,*OldIrq2);
+ CTESpinLock(pConnEle,*OldIrq);
+
+ }
+ else
+ status = STATUS_UNSUCCESSFUL;
+ }
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+ReConnect(
+ IN PVOID Context
+ )
+
+/*++
+Routine Description:
+
+ This Routine handles seting up a DPC to send a session pdu so that the stack
+ does not get wound up in multiple sends for the keep alive timeout case.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ TDI_REQUEST TdiRequest;
+ NTSTATUS status;
+ tCONNECTELE *pConnEle;
+ PVOID DestAddr;
+ CTELockHandle OldIrq;
+ PCTE_IRP pIrp;
+
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
+ CHECK_PTR(pTracker);
+ pConnEle = pTracker->Connect.pConnEle;
+
+ pTracker->Connect.pTimer = NULL;
+ if (pTracker->Flags & TRACKER_CANCELLED)
+ {
+ CTELockHandle OldIrq1;
+
+ //
+ // the the connection setup got cancelled, return the connect irp
+ //
+
+ CTESpinLock(pConnEle,OldIrq1);
+ if (pIrp = pConnEle->pIrp)
+ {
+ pConnEle->pIrp = NULL;
+ CTESpinFree(pConnEle,OldIrq1);
+
+ CTEIoComplete(pIrp,STATUS_CANCELLED,0);
+ } else {
+ CTESpinFree(pConnEle,OldIrq1);
+ }
+
+ //
+ // if SessionSetupContinue has run, it has set the refcount to zero
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (pTracker->RefConn == 0)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
+ }
+ else
+ {
+ pTracker->RefConn--;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ return;
+
+ }
+
+ TdiRequest.Handle.ConnectionContext = pConnEle;
+ // for retarget this is the destination address to connect to.
+ DestAddr = ((NBT_WORK_ITEM_CONTEXT *)Context)->pClientContext;
+
+ PUSH_LOCATION(0x85);
+ pConnEle->state = NBT_ASSOCIATED;
+ status = NbtConnect(&TdiRequest,
+ NULL,
+ NULL,
+ (PTDI_CONNECTION_INFORMATION)pTracker,
+ (PIRP)DestAddr);
+
+ CTEMemFree(Context);
+
+ if (!NT_SUCCESS(status))
+ {
+ // Reset the Irp pending flag
+ // No need to do this - pending has already be returned.
+ //CTEResetIrpPending(pConnEle->pIrp);
+
+ //
+ // tell the client that the session setup failed
+ //
+ CTELockHandle OldIrq1;
+
+ CTESpinLock(pConnEle,OldIrq1);
+ if (pIrp = pConnEle->pIrp)
+ {
+ pConnEle->pIrp = NULL;
+ CTESpinFree(pConnEle,OldIrq1);
+
+ CTEIoComplete( pConnEle->pIrp, STATUS_REMOTE_NOT_LISTENING, 0 ) ;
+ } else {
+ CTESpinFree(pConnEle,OldIrq1);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtConnect(
+ IN TDI_REQUEST *pRequest,
+ IN PVOID pTimeout,
+ IN PTDI_CONNECTION_INFORMATION pCallInfo,
+ IN PTDI_CONNECTION_INFORMATION pReturnInfo,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles setting up a connection (netbios session) to
+ destination. This routine is also called by the Reconnect code when
+ doing a Retarget or trying to reach a destination that does not have
+ a listen currently posted. In this case the parameters mean different
+ things. pIrp could be a new Ipaddress to use (Retarget) and pCallinfo
+ will be null.
+
+Arguments:
+
+
+Return Value:
+
+ TDI_STATUS - status of the request
+
+--*/
+
+{
+ tCONNECTELE *pConnEle;
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+
+
+ pConnEle = pRequest->Handle.ConnectionContext;
+
+ //
+ // this code handles the When DHCP has not assigned an IP address yet
+ //
+
+ if (pCallInfo)
+ {
+ BOOLEAN fNoIpAddress;
+
+ fNoIpAddress =
+ (!pConnEle->pClientEle->pDeviceContext->pSessionFileObject) ||
+ (pConnEle->pClientEle->pDeviceContext->IpAddress == 0);
+#ifdef RASAUTODIAL
+ if (fNoIpAddress && fAcdLoadedG) {
+ CTELockHandle adirql;
+ BOOLEAN fEnabled;
+
+ //
+ // There is no IP address assigned to the interface,
+ // attempt to create an automatic connection.
+ //
+ CTEGetLock(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled) {
+ //
+ // Set a special cancel routine on the irp
+ // in case we get cancelled during the
+ // automatic connection.
+ //
+ (VOID)NTSetCancelRoutine(
+ pIrp,
+ NbtCancelPreConnect,
+ pConnEle->pClientEle->pDeviceContext);
+ if (NbtAttemptAutoDial(
+ pConnEle,
+ pTimeout,
+ pCallInfo,
+ pReturnInfo,
+ pIrp,
+ 0,
+ NbtRetryPreConnect))
+ {
+ return STATUS_PENDING;
+ }
+ //
+ // We did not enqueue the irp on the
+ // automatic connection driver, so
+ // clear the cancel routine we set
+ // above.
+ //
+ (VOID)NTCancelCancelRoutine(pIrp);
+ }
+ }
+#endif // RASAUTODIAL
+ if (fNoIpAddress) {
+ return(STATUS_BAD_NETWORK_PATH);
+ }
+
+ // check the connection element for validity
+ CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status)
+
+ }
+ return NbtConnectCommon(pRequest, pTimeout, pCallInfo, pReturnInfo, pIrp);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtConnectCommon(
+ IN TDI_REQUEST *pRequest,
+ IN PVOID pTimeout,
+ IN PTDI_CONNECTION_INFORMATION pCallInfo,
+ IN PTDI_CONNECTION_INFORMATION pReturnInfo,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles setting up a connection (netbios session) to
+ destination. This routine is also called by the Reconnect code when
+ doing a Retarget or trying to reach a destination that does not have
+ a listen currently posted. In this case the parameters mean different
+ things. pIrp could be a new Ipaddress to use (Retarget) and pCallinfo
+ will be null.
+
+Arguments:
+
+
+Return Value:
+
+ TDI_STATUS - status of the request
+
+--*/
+
+{
+ tCONNECTELE *pConnEle;
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ ULONG IpAddress;
+ PCHAR pToName;
+ USHORT sLength;
+ tSESSIONREQ *pSessionReq = NULL;
+ PUCHAR pCopyTo;
+ tCLIENTELE *pClientEle;
+ LONG NameType;
+ ULONG NameLen;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tNAMEADDR *pNameAddr;
+ tLOWERCONNECTION *pLowerConn;
+ tDEVICECONTEXT *pDeviceContext;
+ NBT_WORK_ITEM_CONTEXT *pContext;
+ ULONG RemoteIpAddress;
+
+
+ pConnEle = pRequest->Handle.ConnectionContext;
+ //
+ // Acquire this resource to co-ordinate with DHCP changing the IP
+ // address
+ CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
+
+ CTESpinLock(pConnEle,OldIrq);
+ if ((pConnEle->state != NBT_ASSOCIATED) &&
+ (pConnEle->state != NBT_DISCONNECTED))
+ {
+ // the connection is Idle and is not associated with an address
+ // so reject the connect attempt
+ //
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ goto ExitProc2;
+ }
+
+ pClientEle = pConnEle->pClientEle;
+ CTESpinLock(pClientEle,OldIrq1);
+ if ( pClientEle->Verify != NBT_VERIFY_CLIENT )
+ {
+ if ( pClientEle->Verify == NBT_VERIFY_CLIENT_DOWN )
+ {
+ status = STATUS_CANCELLED;
+ }
+ else
+ {
+ status = STATUS_INVALID_HANDLE;
+ }
+ goto ExitProc;
+ }
+
+ //
+ // BUGBUG - Should be using pDeviceContext lock instead of
+ // NbtConfig.Resource, above.
+ //
+ pDeviceContext = pClientEle->pDeviceContext;
+ //
+ // this code handles the case when DHCP has not assigned an IP address yet
+ //
+ if (
+ ( (pCallInfo) && (!pDeviceContext->pSessionFileObject) )
+ || (pDeviceContext->IpAddress == 0)
+ )
+ {
+ status = STATUS_BAD_NETWORK_PATH;
+ goto ExitProc;
+ }
+
+ //
+ // check if the Reconnect got cancelled
+ //
+ if (!pCallInfo)
+ {
+ pTracker = (tDGRAM_SEND_TRACKING *)pReturnInfo;
+ if (pTracker->Flags & TRACKER_CANCELLED)
+ {
+ //
+ // the connect attempt got cancelled while waiting for
+ // the reconnect routine to run
+ //
+ //
+ // if SessionSetupContinue has run, it has set the refcount to zero
+ //
+ if (pTracker->RefConn == 0)
+ {
+ FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
+ }
+ else
+ {
+ pTracker->RefConn--;
+ }
+ status = STATUS_CANCELLED;
+ goto ExitProc;
+ }
+ }
+
+ // be sure the name is in the correct state for a connection
+ //
+ if (pClientEle->pAddress->pNameAddr->NameTypeState & STATE_CONFLICT)
+ {
+ status = STATUS_DUPLICATE_NAME;
+ goto ExitProc;
+ }
+
+ pConnEle->state = NBT_CONNECTING;
+
+ // Increment the ref count so that a cleanup cannot remove
+ // the pConnEle till the session is setup - one if these is removed when
+ // the session is setup and the other is removed when it is disconnected.
+ //
+ pConnEle->RefCount += 2;
+ //ASSERT(pConnEle->RefCount == 3);
+
+ //
+ // unlink the connection from the idle connection list and put on active list
+ //
+ RemoveEntryList(&pConnEle->Linkage);
+ InsertTailList(&pClientEle->ConnectActive,&pConnEle->Linkage);
+
+ // this field is used to hold a disconnect irp if it comes down during
+ // NBT_CONNECTING or NBT_SESSION_OUTBOUND states
+ //
+ pConnEle->pIrpDisc = NULL;
+
+ // if null then this is being called to reconnect and the tracker is already
+ // setup.
+ //
+ if (pCallInfo)
+ {
+ PTRANSPORT_ADDRESS pRemoteAddress;
+ PTA_NETBIOS_ADDRESS pRemoteNetBiosAddress;
+ PTA_NETBIOS_EX_ADDRESS pRemoteNetbiosExAddress;
+ ULONG TdiAddressType;
+
+ // we must store the client's irp in the connection element so that when
+ // the session sets up, we can complete the Irp.
+ pConnEle->pIrp = (PVOID)pIrp;
+ pConnEle->Orig = TRUE;
+ pConnEle->SessionSetupCount = NBT_SESSION_SETUP_COUNT-1; // -1 for this attempt
+
+ pRemoteAddress = (PTRANSPORT_ADDRESS)pCallInfo->RemoteAddress;
+ TdiAddressType = pRemoteAddress->Address[0].AddressType;
+ pConnEle->pClientEle->AddressType = TdiAddressType;
+ pConnEle->AddressType = TdiAddressType;
+
+ if (TdiAddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) {
+ PTDI_ADDRESS_NETBIOS pNetbiosAddress;
+
+ pRemoteNetbiosExAddress = (PTA_NETBIOS_EX_ADDRESS)pRemoteAddress;
+
+ CTEMemCopy(pConnEle->pClientEle->EndpointName,
+ pRemoteNetbiosExAddress->Address[0].Address[0].EndpointName,
+ sizeof(pRemoteNetbiosExAddress->Address[0].Address[0].EndpointName));
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NetBt:Handling New Address Type with SessionName %16s\n",
+ pConnEle->pClientEle->EndpointName));
+
+ pNetbiosAddress = &pRemoteNetbiosExAddress->Address[0].Address[0].NetbiosAddress;
+ pToName = pNetbiosAddress->NetbiosName;
+ NameType = pNetbiosAddress->NetbiosNameType;
+ NameLen = pRemoteNetbiosExAddress->Address[0].AddressLength -
+ FIELD_OFFSET(TDI_ADDRESS_NETBIOS_EX,NetbiosAddress) -
+ FIELD_OFFSET(TDI_ADDRESS_NETBIOS,NetbiosName);
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NetBt:NETBIOS address NameLen(%ld) Name %16s\n",NameLen,pToName));
+ status = STATUS_SUCCESS;
+ } else if (TdiAddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ pRemoteNetBiosAddress = (PTA_NETBIOS_ADDRESS)pRemoteAddress;
+ status = GetNetBiosNameFromTransportAddress(
+ pRemoteNetBiosAddress,
+ &pToName,
+ &NameLen,
+ &NameType);
+ } else {
+ status = STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ if(!NT_SUCCESS(status))
+ {
+ pConnEle->state = NBT_ASSOCIATED;
+ goto ExitProc1;
+ }
+
+ // get a buffer for tracking Session setup
+ status = GetTracker(&pTracker);
+ if (!NT_SUCCESS(status))
+ {
+ pConnEle->state = NBT_ASSOCIATED;
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ExitProc1;
+ }
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NbtConnectCommon:Tracker %lx\n",pTracker));
+
+ // save this in case we need to do a reconnect later and need the
+ // destination name again.
+ pTracker->SendBuffer.pBuffer = NbtAllocMem(NameLen,NBT_TAG('F'));
+ if (!pTracker->SendBuffer.pBuffer)
+ {
+ pConnEle->state = NBT_ASSOCIATED;
+ FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ExitProc1;
+ }
+ CTEMemCopy(pTracker->SendBuffer.pBuffer,pToName,NameLen);
+
+ CHECK_PTR(&pTracker);
+ pTracker->SendBuffer.Length = NameLen;
+ pTracker->pClientIrp = pIrp;
+ pTracker->RefConn = 1;
+ pTracker->Flags = SESSION_SETUP_FLAG;
+
+
+ CTESpinFree(pClientEle,OldIrq1);
+ CTESpinFree(pConnEle,OldIrq);
+
+ pTracker->Connect.pDeviceContext = pDeviceContext;
+ pTracker->Connect.pConnEle = (PVOID)pConnEle;
+ pTracker->DestPort = NBT_SESSION_TCP_PORT;
+
+ // this is a ptr to the name in the client's, Irp, so that address must
+ // remain valid until this completes. It should be valid, because we
+ // do not complete the Irp until the transaction completes. This ptr
+ // is overwritten when the name resolves, so that it points the the
+ // pNameAddr in the hash table.
+ //
+ pTracker->Connect.pDestName = pTracker->SendBuffer.pBuffer;
+
+ // the timeout value is passed on through to the transport
+ pTracker->Connect.pTimeout = pTimeout;
+
+ // the length is the 4 byte session hdr length + the half ascii calling
+ // and called names + the scope length times 2, one for each name
+ //
+ sLength = sizeof(tSESSIONREQ) + (NETBIOS_NAME_SIZE << 2)
+ + (NbtConfig.ScopeLength <<1);
+
+ status = STATUS_INSUFFICIENT_RESOURCES ;
+ pSessionReq = (tSESSIONREQ *)NbtAllocMem(sLength,NBT_TAG('G'));
+ if (!pSessionReq)
+ {
+ goto NbtConnect_Error;
+ }
+
+ pTracker->SendBuffer.pDgramHdr = pSessionReq;
+
+ //
+ // Save the remote name while we still have it
+ //
+ CTEMemCopy( pConnEle->RemoteName,
+ pToName,
+ NETBIOS_NAME_SIZE ) ;
+
+ }
+ else
+ {
+ // for the reconnect case we must skip most of the processing since
+ // the tracker is all set up already. All we need to do is
+ // retry the connection.
+ pTracker = (tDGRAM_SEND_TRACKING *)pReturnInfo;
+ pTracker->RefConn++;
+ NameLen = NETBIOS_NAME_SIZE;
+ CTESpinFree(pClientEle,OldIrq1);
+ CTESpinFree(pConnEle,OldIrq);
+ }
+
+ // for the reconnect case a null pCallInfo gets us into this If
+ if (!pCallInfo || pSessionReq)
+ {
+
+ if (pCallInfo)
+ {
+ PCHAR pSessionName;
+
+ if (pConnEle->pClientEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) {
+ pSessionName = pConnEle->pClientEle->EndpointName;
+ } else {
+ pSessionName = pToName;
+ }
+
+ pSessionReq->Hdr.Type = NBT_SESSION_REQUEST;
+ pSessionReq->Hdr.Flags = NBT_SESSION_FLAGS;
+ pSessionReq->Hdr.Length = (USHORT)htons(sLength- (USHORT)sizeof(tSESSIONHDR)); // size of called and calling NB names.
+
+ pTracker->SendBuffer.HdrLength = (ULONG)sLength;
+
+ // put the Dest HalfAscii name into the Session Pdu
+ pCopyTo = ConvertToHalfAscii( (PCHAR)&pSessionReq->CalledName.NameLength,
+ pSessionName,
+ NbtConfig.pScope,
+ NbtConfig.ScopeLength);
+
+ // put the Source HalfAscii name into the Session Pdu
+ pCopyTo = ConvertToHalfAscii(pCopyTo,
+ ((tADDRESSELE *)pClientEle->pAddress)->pNameAddr->Name,
+ NbtConfig.pScope,
+ NbtConfig.ScopeLength);
+
+
+ }
+
+
+ // open a connection with the transport for this session
+ status = TdiOpenandAssocConnection(
+ pConnEle,
+ pDeviceContext,
+ 0); // 0 for PortNumber means any port
+
+ if (NT_SUCCESS(status))
+ {
+ tLOWERCONNECTION *pLowerDump;
+ PLIST_ENTRY pEntry;
+
+ // We need to track that this side originated the call so we discard this
+ // connection at the end
+ //
+ pConnEle->pLowerConnId->bOriginator = TRUE;
+
+ // set this state to associated so that the cancel irp routine
+ // can differentiate the name query stage from the setupconnection
+ // stage since pConnEle is in the Nbtconnecting state for both.
+ //
+ pConnEle->pLowerConnId->State = NBT_ASSOCIATED;
+
+ // store the tracker in the Irp Rcv ptr so it can be used by the
+ // session setup code in hndlrs.c in the event the destination is
+ // between posting listens and this code should re-attempt the
+ // session setup. The code in hndlrs.c returns the tracker to its
+ // free list and frees the session hdr memory too.
+ //
+ pConnEle->pIrpRcv = (PIRP)pTracker;
+
+ // if this routine is called to do a reconnect, DO NOT close another
+ // Lower Connection since one was closed the on the first
+ // connect attempt.
+ if (pCallInfo)
+ {
+ //
+ // remove a lower connection from the free list attached to the device
+ // context since when this pConnEle was created, a lower connectin
+ // was created then incase inbound calls were to be accepted on the
+ // connection. But since it is an outbound call, remove a lower
+ // connection.
+ //
+ CTESpinLock(pDeviceContext,OldIrq1);
+ if (!pConnEle->LowerConnBlockRemoved &&
+ !IsListEmpty(&pDeviceContext->LowerConnFreeHead))
+ {
+ pEntry = RemoveHeadList(&pDeviceContext->LowerConnFreeHead);
+ pLowerDump = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
+
+ pConnEle->LowerConnBlockRemoved = TRUE;
+ CTESpinFree(pDeviceContext,OldIrq1);
+
+ //
+ // close the lower connection with the transport
+ //
+#ifndef VXD
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:On Connect,close handle(from pool) %X -> %X\n",pLowerDump,pLowerDump->FileHandle));
+#else
+ KdPrint(("Nbt:Closing Handle %X -> %X\n",pLowerDump,pLowerDump->pFileObject));
+#endif
+ //NTDereferenceObject((PVOID *)pLowerDump->pFileObject);
+ //NbtTdiCloseConnection(pLowerDump);
+
+ NbtDereferenceLowerConnection(pLowerDump);
+ }
+ else
+ {
+ CTESpinFree(pDeviceContext,OldIrq1);
+ }
+
+
+ }
+ else
+ {
+ // the original "ToName" was stashed in this unused
+ // ptr! - for the Reconnect case
+ pToName = pTracker->Connect.pConnEle->RemoteName;
+ // the pNameAddr part of pTracker(pDestName) needs to pt. to
+ // the name so that SessionSetupContinue can find the name
+ pTracker->Connect.pDestName = pToName;
+
+ }
+
+ //
+ // find the destination IP address
+ //
+
+ //
+ // if the name is longer than 16 bytes, it's not a netbios name.
+ // skip wins, broadcast etc. and go straight to dns resolution
+ //
+
+ if (pConnEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) {
+ RemoteIpAddress = Nbt_inet_addr(pToName);
+ } else {
+ RemoteIpAddress = 0;
+ }
+
+ if (RemoteIpAddress != 0) {
+ tNAMEADDR *pRemoteNameAddr;
+
+ //
+ // add this server name to the remote hashtable
+ //
+
+ pRemoteNameAddr = NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('8'));
+ if (pRemoteNameAddr != NULL)
+ {
+ tNAMEADDR *pTableAddress;
+
+ CTEZeroMemory(pRemoteNameAddr,sizeof(tNAMEADDR));
+ InitializeListHead(&pRemoteNameAddr->Linkage);
+ CTEMemCopy(pRemoteNameAddr->Name,pToName,NETBIOS_NAME_SIZE);
+ pRemoteNameAddr->Verify = REMOTE_NAME;
+ pRemoteNameAddr->RefCount = 1;
+ pRemoteNameAddr->NameTypeState = STATE_RESOLVED | NAMETYPE_UNIQUE;
+ pRemoteNameAddr->AdapterMask = (CTEULONGLONG)-1;
+ pRemoteNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
+ pRemoteNameAddr->IpAddress = RemoteIpAddress;
+
+ status = AddToHashTable(
+ NbtConfig.pRemoteHashTbl,
+ pRemoteNameAddr->Name,
+ NbtConfig.pScope,
+ 0,
+ 0,
+ pRemoteNameAddr,
+ &pTableAddress);
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NbtConnectCommon ...AddRecordToHashTable %s Status %lx\n",pRemoteNameAddr->Name,status));
+ } else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (status == STATUS_SUCCESS) {
+ SessionSetupContinue(pTracker,status);
+ status = STATUS_PENDING;
+ }
+ } else {
+// if ((pConnEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) ||
+// (NameLen > NETBIOS_NAME_SIZE)) {
+ if (NameLen > NETBIOS_NAME_SIZE) {
+ pTracker->AddressType = pConnEle->AddressType;
+ if (pConnEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) {
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("$$$$$ Avoiding NETBIOS name translation on connection to %16s\n",pConnEle->RemoteName));
+ }
+ pContext = (NBT_WORK_ITEM_CONTEXT *)NbtAllocMem(sizeof(NBT_WORK_ITEM_CONTEXT),NBT_TAG('H'));
+ if (!pContext)
+ {
+ KdPrint(("Nbt: NbtConnect: couldn't alloc mem for pContext\n"));
+ goto NbtConnect_Error;
+ }
+
+ pContext->pTracker = NULL; // no query tracker
+ pContext->pClientContext = pTracker; // the client tracker
+ pContext->ClientCompletion = SessionSetupContinue;
+ status = DoDnsResolve(pContext);
+ } else {
+ status = FindNameOrQuery(pTracker,
+ pToName,
+ pDeviceContext,
+ SessionSetupContinue,
+ &pConnEle->pTracker,
+ TRUE,
+ &pNameAddr);
+ }
+ }
+
+ if (status == STATUS_SUCCESS)
+ {
+ //
+ // for destinations on this machine use this devicecontext's
+ // ip address
+ //
+ if (pNameAddr->Verify == REMOTE_NAME)
+ {
+ IpAddress = pNameAddr->IpAddress;
+ }
+ else
+ {
+ IpAddress = pDeviceContext->IpAddress;
+ }
+ }
+
+ // There may be a valid name address to use or it may have been
+ // nulled out to signify "Do Another Name Query"
+ if (!pCallInfo && pIrp)
+ {
+ // for the ReTarget case the Ip address is passed in the
+ // irp parameter
+ IpAddress = (ULONG)pIrp;
+ }
+
+ //
+ // be sure that a close or disconnect has not come down and
+ // cancelled the tracker
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (status == STATUS_SUCCESS)
+ {
+ if ((pTracker->Flags & TRACKER_CANCELLED))
+ {
+ NbtDereferenceName(pNameAddr);
+ status = STATUS_CANCELLED;
+ }
+ else
+ if ((pNameAddr->NameTypeState & NAMETYPE_UNIQUE ) ||
+ (NodeType & BNODE))
+ {
+ // set the session state to NBT_CONNECTING
+ CHECK_PTR(((tCONNECTELE *)pTracker->Connect.pConnEle));
+ ((tCONNECTELE *)pTracker->Connect.pConnEle)->state = NBT_CONNECTING;
+ ((tCONNECTELE *)pTracker->Connect.pConnEle)->BytesRcvd = 0;;
+ ((tCONNECTELE *)pTracker->Connect.pConnEle)->ReceiveIndicated = 0;
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Setting Up Session(cached entry!!) to %16.16s <%X>, %X\n",
+ pNameAddr->Name,pNameAddr->Name[15],(ULONG)pConnEle));
+
+ CHECK_PTR(pConnEle);
+ // keep track of the other end's ip address
+ pConnEle->pLowerConnId->SrcIpAddr = htonl(IpAddress);
+ pConnEle->pLowerConnId->State = NBT_CONNECTING;
+
+ pConnEle->pTracker = NULL;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ status = TcpSessionStart(
+ pTracker,
+ IpAddress,
+ (tDEVICECONTEXT *)pTracker->Connect.pDeviceContext,
+ SessionStartupContinue,
+ pTracker->DestPort);
+
+ //
+ // if TcpSessionStart fails for some reason it will still
+ // call the completion routine which will look after
+ // cleaning up
+ //
+
+ CTEExReleaseResource(&NbtConfig.Resource);
+
+#ifdef RASAUTODIAL
+ //
+ // Notify the automatic connection driver
+ // of the successful connection.
+ //
+ if (fAcdLoadedG && NT_SUCCESS(status)) {
+ CTELockHandle adirql;
+ BOOLEAN fEnabled;
+
+ CTEGetLock(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled)
+ NbtNoteNewConnection(pConnEle, pNameAddr);
+ }
+#endif // RASAUTODIAL
+
+ return(status);
+ }
+ else
+ {
+
+ // the destination is a group name...
+ NbtDereferenceName(pNameAddr);
+ status = STATUS_BAD_NETWORK_PATH;
+ }
+
+
+ }
+ else
+ if (NT_SUCCESS(status))
+ {
+ // i.e. pending was returned rather than success
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ CTEExReleaseResource(&NbtConfig.Resource);
+ return(status);
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ }
+
+ }
+
+
+NbtConnect_Error:
+
+ //
+ // *** Error Handling Here ***
+ //
+ //
+ // unlink from the active connection list and put on idle list
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CTESpinLock(pConnEle,OldIrq1);
+
+ pLowerConn = pConnEle->pLowerConnId;
+
+ CHECK_PTR(pConnEle);
+ pConnEle->pLowerConnId = NULL;
+
+ pConnEle->state = NBT_ASSOCIATED;
+ RelistConnection(pConnEle);
+
+ if (pLowerConn)
+ {
+ CHECK_PTR(pLowerConn);
+ pLowerConn->pUpperConnection = NULL;
+
+
+ CTESpinFree(pConnEle,OldIrq1);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // undo the reference done in nbtconnect
+ DereferenceIfNotInRcvHandler(pConnEle,pLowerConn);
+
+ // need to increment the ref count for CleanupAfterDisconnect to
+ // work correctly since it assumes the connection got fully connected
+ //
+ CTEInterlockedIncrementLong(&pLowerConn->RefCount);
+ ASSERT(pLowerConn->RefCount == 2);
+#if !defined(VXD) && DBG
+ //
+ // DEBUG to catch upper connections being put on lower conn QUEUE
+ //
+ if ((pLowerConn->Verify != NBT_VERIFY_LOWERCONN ) ||
+ (pLowerConn->RefCount == 1))
+ {
+ DbgBreakPoint();
+ }
+#endif
+
+ (void) CTEQueueForNonDispProcessing( NULL,
+ pLowerConn,
+ NULL,
+ CleanupAfterDisconnect,
+ pLowerConn->pDeviceContext);
+
+ }
+ else
+ {
+ CTESpinFree(pConnEle,OldIrq1);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ NbtDereferenceConnection(pConnEle);
+ }
+
+ FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
+
+ //
+ // Undo the second reference done above
+ //
+ NbtDereferenceConnection(pConnEle);
+
+ CTEExReleaseResource(&NbtConfig.Resource);
+ return(status);
+
+
+ExitProc1:
+
+ RemoveEntryList(&pConnEle->Linkage);
+ InsertTailList(&pClientEle->ConnectHead,&pConnEle->Linkage);
+ pConnEle->RefCount--;
+ pConnEle->RefCount--;
+
+ExitProc:
+ CTESpinFree(pClientEle,OldIrq1);
+ExitProc2:
+ CTESpinFree(pConnEle,OldIrq);
+ CTEExReleaseResource(&NbtConfig.Resource);
+ return(status);
+
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+CleanUpPartialConnection(
+ IN NTSTATUS status,
+ IN tCONNECTELE *pConnEle,
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PIRP pClientIrp,
+ IN CTELockHandle irqlJointLock,
+ IN CTELockHandle irqlConnEle
+ )
+{
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ PIRP pIrpDisc;
+
+ //
+ // we had allocated this in nbtconnect
+ //
+ if (pTracker->SendBuffer.pBuffer)
+ {
+ CTEFreeMem(pTracker->SendBuffer.pBuffer);
+ pTracker->SendBuffer.pBuffer = NULL;
+ }
+
+ FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
+
+ if (pConnEle->state != NBT_IDLE)
+ {
+ pConnEle->state = NBT_ASSOCIATED;
+ }
+
+ CTESpinFree(pConnEle,irqlConnEle);
+ CTESpinFree(&NbtConfig.JointLock,irqlJointLock);
+
+ //
+ // If the tracker is cancelled then NbtDisconnect has run and there is
+ // a disconnect irp waiting to be returned.
+ //
+ pIrpDisc = NULL;
+ if (pTracker->Flags & TRACKER_CANCELLED)
+ {
+ //
+ // Complete the disconnect irp now too
+ //
+ pIrpDisc = pConnEle->pIrpDisc;
+
+ status = STATUS_CANCELLED;
+ }
+
+ //
+ // this will close the lower connection and dereference pConnEle once.
+ //
+ QueueCleanup(pConnEle);
+
+ //
+ // If the state is IDLE it means that NbtCleanupConnection has run and
+ // the connection has been removed from the list so don't add it to
+ // the list again
+ //
+ CTESpinLock(pConnEle,irqlConnEle);
+ if (pConnEle->state != NBT_IDLE)
+ {
+ RelistConnection(pConnEle);
+ }
+ CTESpinFree(pConnEle,irqlConnEle);
+
+ //
+ // remove the last reference added in nbt connect. The refcount will be 2
+ // if nbtcleanupconnection has not run and 1, if it has. So this call
+ // could free pConnEle.
+ //
+ NbtDereferenceConnection(pConnEle);
+
+ if (status == STATUS_TIMEOUT)
+ {
+ status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ CTEIoComplete(pClientIrp,status,0L);
+
+ //
+ // This is a disconnect irp that has been queued till the name query
+ // completed
+ //
+ if (pIrpDisc)
+ {
+ CTEIoComplete(pIrpDisc,STATUS_SUCCESS,0L);
+ }
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SessionSetupContinue(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ )
+/*++
+
+Routine Description
+
+ This routine handles setting up a session after a name has been resolved
+ to an IP address.
+
+ This routine is given as the completion routine to the "QueryNameOnNet" call
+ in NbtConnect, above. When a name query response comes in or the
+ timer times out after N retries, this routine is called passing STATUS_TIMEOUT
+ for a failure.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ tNAMEADDR *pNameAddr;
+ ULONG lNameType;
+ PIRP pClientIrp;
+ PIRP pIrpDisc;
+ ULONG IpAddress;
+ tCONNECTELE *pConnEle;
+ tLOWERCONNECTION *pLowerConn;
+ BOOLEAN TrackerCancelled;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ pConnEle = pTracker->Connect.pConnEle;
+
+ CTESpinLock(pConnEle,OldIrq);
+ pLowerConn = pConnEle->pLowerConnId;
+
+ TrackerCancelled = pTracker->Flags & TRACKER_CANCELLED;
+
+ if (status == STATUS_SUCCESS && !TrackerCancelled)
+ {
+ // this is the QueryOnNet Tracker ptr being cleared rather than the
+ // session setup tracker.
+ //
+ CHECK_PTR(pConnEle);
+ pConnEle->pTracker = NULL;
+
+ // check the Remote table and then the Local table
+ //
+ pNameAddr = FindNameRemoteThenLocal(pTracker,&lNameType);
+
+ if (pNameAddr)
+ {
+ // for a call to ourselves, use the ip address of this
+ // device context
+ //
+ if (pNameAddr->Verify == REMOTE_NAME)
+ {
+ IpAddress = pNameAddr->IpAddress;
+ }
+ else
+ {
+ IpAddress = pConnEle->pClientEle->pDeviceContext->IpAddress;
+ }
+
+ // a session can only be started with a unique named destination
+ if ((lNameType & NAMETYPE_UNIQUE ) || (NodeType & BNODE))
+ {
+ // set the session state, initialize a few things and setup a
+ // TCP connection, calling SessionStartupContinue when the TCP
+ // connection is up
+ //
+ CHECK_PTR(pConnEle);
+ pLowerConn->State = NBT_CONNECTING;
+
+ pConnEle->state = NBT_CONNECTING;
+ pConnEle->BytesRcvd = 0;;
+ pConnEle->ReceiveIndicated = 0;
+ CHECK_PTR(pTracker);
+ pTracker->Connect.pNameAddr = pNameAddr;
+
+ // keep track of the other end's ip address
+ pConnEle->pLowerConnId->SrcIpAddr = htonl(IpAddress);
+ pConnEle->pTracker = NULL; // cleanup connection uses this check
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Setting Up Session(after Query) to %16.16s <%X>, %X\n",
+ pNameAddr->Name,pNameAddr->Name[15],
+ (ULONG)pTracker->Connect.pConnEle));
+
+ // increment so the name cannot disappear and to be consistent
+ // with FindNameOrQuery , which increments the refcount, so
+ // we always need to deref it when the connection is setup.
+ //
+ pNameAddr->RefCount++;
+ // DEBUG
+ ASSERT(pNameAddr->RefCount >= 2);
+ CTESpinFree(pConnEle,OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // start the session...
+ status = TcpSessionStart(
+ pTracker,
+ IpAddress,
+ (tDEVICECONTEXT *)pTracker->Connect.pDeviceContext,
+ SessionStartupContinue,
+ pTracker->DestPort);
+
+
+ //
+ // the only failure that could occur is if the pLowerConn
+ // got separated from pConnEle, in which case some other
+ // part of the code has disconnected and cleanedup, so
+ // just return
+ //
+
+#ifdef RASAUTODIAL
+ //
+ // Notify the automatic connection driver
+ // of the successful connection.
+ //
+ if (fAcdLoadedG && NT_SUCCESS(status)) {
+ CTELockHandle adirql;
+ BOOLEAN fEnabled;
+
+ CTEGetLock(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled)
+ NbtNoteNewConnection(pConnEle, pNameAddr);
+ }
+#endif // RASAUTODIAL
+
+ return;
+
+ }
+
+ }
+ status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ pClientIrp = pConnEle->pIrp;
+ pConnEle->pIrp = NULL;
+
+#ifdef RASAUTODIAL
+ //
+ // Before we return an error, give this
+ // address to the automatic connection driver
+ // to see if it can create a new network
+ // connection.
+ //
+ if (fAcdLoadedG &&
+ !TrackerCancelled &&
+ status == STATUS_BAD_NETWORK_PATH)
+ {
+ CTELockHandle adirql;
+ BOOLEAN fEnabled;
+
+ CTEGetLock(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled &&
+ NbtAttemptAutoDial(
+ pConnEle,
+ pTracker->Connect.pTimeout,
+ NULL,
+ (PTDI_CONNECTION_INFORMATION)pTracker,
+ pClientIrp,
+ 0,
+ NbtRetryPostConnect))
+ {
+ CTESpinFree(pConnEle,OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return;
+ }
+ }
+#endif // RASAUTODIAL
+
+ CleanUpPartialConnection(status, pConnEle, pTracker, pClientIrp, OldIrq1, OldIrq);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+QueueCleanup(
+ IN tCONNECTELE *pConnEle
+ )
+/*++
+Routine Description
+
+ This routine handles Queuing a request to a worker thread to cleanup
+ a connection(which basically closes the connection).
+
+Arguments:
+
+ pConnEle - ptr to the upper connection
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ CTELockHandle OldIrq2;
+ ULONG State;
+ BOOLEAN DerefConnEle;
+ tLOWERCONNECTION *pLowerConn;
+
+ CHECK_PTR(pConnEle);
+ if (pConnEle)
+ {
+
+ // to coordinate with RejectSession in hndlrs.c get the spin lock
+ // so we don't disconnect twice.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ pLowerConn = pConnEle->pLowerConnId;
+
+ if (pLowerConn &&
+ (pLowerConn->State > NBT_IDLE) &&
+ (pLowerConn->State < NBT_DISCONNECTING))
+ {
+ CTESpinLock(pConnEle,OldIrq2);
+ CTESpinLock(pLowerConn,OldIrq);
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:QueueCleanup, State=%X, Lower=%X Upper=%X\n",
+ pLowerConn->State,
+ pLowerConn,pLowerConn->pUpperConnection));
+
+ CHECK_PTR(pLowerConn);
+ State = pLowerConn->State;
+
+ pLowerConn->State = NBT_DISCONNECTING;
+
+ if (pConnEle->state != NBT_IDLE)
+ {
+ pConnEle->state = NBT_DISCONNECTED;
+ }
+
+ pConnEle->pLowerConnId = NULL;
+ pLowerConn->pUpperConnection = NULL;
+
+ //
+ // need to increment the ref count for CleanupAfterDisconnect to
+ // work correctly since it assumes the connection got fully connected
+ // Note: if this routine is called AFTER the connection is fully
+ // connected such as in SessionTimedOut, then RefCount must
+ // be decremented there to account for this increment.
+ //
+ if (State < NBT_SESSION_OUTBOUND)
+ {
+ pLowerConn->RefCount++;
+ }
+
+
+
+#if !defined(VXD) && DBG
+ //
+ // DEBUG to catch upper connections being put on lower conn QUEUE
+ //
+ if ((pLowerConn->Verify != NBT_VERIFY_LOWERCONN ) ||
+ (pLowerConn->RefCount == 1))
+ {
+ DbgBreakPoint();
+ }
+#endif
+ CTESpinFree(pLowerConn,OldIrq);
+ CTESpinFree(pConnEle,OldIrq2);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ //
+ // when the lower no longer points to the upper undo the reference
+ // done in NbtConnect, or InBound.
+ //
+ DereferenceIfNotInRcvHandler(pConnEle,pLowerConn);
+
+ status = CTEQueueForNonDispProcessing(
+ NULL,
+ pLowerConn,
+ NULL,
+ CleanupAfterDisconnect,
+ pLowerConn->pDeviceContext);
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ }
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+StartSessionTimer(
+ tDGRAM_SEND_TRACKING *pTracker,
+ tCONNECTELE *pConnEle
+ )
+
+/*++
+Routine Description
+
+ This routine handles setting up a timer to time the connection setup.
+ JointLock Spin Lock is held before calling this routine.
+
+Arguments:
+
+ pConnEle - ptr to the connection structure
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG Timeout;
+ CTELockHandle OldIrq;
+ tTIMERQENTRY *pTimerEntry;
+
+
+ CTESpinLock(pConnEle,OldIrq);
+
+
+ CTEGetTimeout(pTracker->Connect.pTimeout,&Timeout);
+
+ // now start a timer to time the return of the session setup
+ // message
+ //
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Start Session Setup Timer TO = %X\n",Timeout));
+
+ if (Timeout < NBT_SESSION_RETRY_TIMEOUT)
+ {
+ Timeout = NBT_SESSION_RETRY_TIMEOUT;
+ }
+ status = StartTimer(
+ Timeout,
+ (PVOID)pTracker, // context value
+ NULL, // context2 value
+ SessionTimedOut,
+ pTracker,
+ SessionTimedOut,
+ 0,
+ &pTimerEntry);
+
+ if (NT_SUCCESS(status))
+ {
+ pTracker->Connect.pTimer = pTimerEntry;
+
+ }
+ else
+ {
+ // we failed to get a timer, but the timer is only used
+ // to handle the destination not responding to it is
+ // not critical to get a timer... so carry on
+ //
+ CHECK_PTR(pTracker);
+ pTracker->Connect.pTimer = NULL;
+
+ }
+
+ CTESpinFree(pConnEle,OldIrq);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SessionStartupContinue(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo)
+/*++
+Routine Description
+
+ This routine handles sending the session request PDU after the TCP
+ connection has been setup to the destination IP address.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ tCONNECTELE *pConnEle;
+ ULONG lSentLength;
+ TDI_REQUEST TdiRequest;
+ PIRP pClientIrp;
+ PIRP pIrpDisc;
+ tLOWERCONNECTION *pLowerConn;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ BOOLEAN TrackerCancelled;
+ tNAMEADDR *pNameAddr;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+ pConnEle = (tCONNECTELE *)pTracker->Connect.pConnEle;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ //
+ // we had allocated this in nbtconnect: we don't need anymore, free it
+ //
+ if (pTracker->SendBuffer.pBuffer)
+ {
+ CTEFreeMem(pTracker->SendBuffer.pBuffer);
+ pTracker->SendBuffer.pBuffer = NULL;
+ }
+
+ //
+ // remove the reference done with FindNameOrQuery was called, or when
+ // SessionSetupContinue ran
+ //
+ NbtDereferenceName(pTracker->Connect.pNameAddr);
+
+ CTESpinLock(pConnEle,OldIrq);
+ pLowerConn = pConnEle->pLowerConnId;
+
+ //
+ // NbtDisconnect can cancel the tracker if a disconnect comes in during
+ // the connecting phase.
+ //
+ if (!(pTracker->Flags & TRACKER_CANCELLED) &&
+ (NT_SUCCESS(status)))
+ {
+
+ // set the session state to NBT_SESSION_OUTBOUND
+ //
+ pConnEle->state = NBT_SESSION_OUTBOUND;
+
+ // in case the connection got disconnected during the setup phase,
+ // check the lower conn value
+ if (pLowerConn)
+ {
+
+
+ //
+ // Increment the reference count on a connection while it is connected
+ // so that it cannot be deleted until it disconnects.
+ //
+ REFERENCE_LOWERCONN(pLowerConn);
+ ASSERT(pLowerConn->RefCount == 2);
+
+ pLowerConn->State = NBT_SESSION_OUTBOUND;
+ pLowerConn->StateRcv = NORMAL;
+
+ SetStateProc( pLowerConn, Outbound ) ;
+
+ // we need to pass the file handle of the connection to TCP.
+ TdiRequest.Handle.AddressHandle = pLowerConn->pFileObject;
+
+ // the completion routine is setup to free the pTracker memory block
+ TdiRequest.RequestNotifyObject = SessionStartupCompletion;
+ TdiRequest.RequestContext = (PVOID)pTracker;
+
+ CTESpinFree(pConnEle,OldIrq);
+
+ //
+ // failure to get a timer causes the connection setup to fail
+ //
+ status = StartSessionTimer(pTracker,pConnEle);
+ if (NT_SUCCESS(status))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ status = NTSetCancelRoutine(pConnEle->pIrp,
+ NTCancelSession,
+ pTracker->pDeviceContext);
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // We have closed down the connection by failing the call to
+ // setup up the cancel routine - it ended up calling the
+ // cancel routine.
+ //
+ //
+ // remove the second reference added in nbtconnect
+ //
+ NbtDereferenceConnection(pConnEle);
+ return;
+ }
+
+ // the only data sent is the session request buffer which is in the pSendinfo
+ // structure.
+ status = TdiSend(
+ &TdiRequest,
+ 0, // send flags are not set
+ pTracker->SendBuffer.HdrLength,
+ &lSentLength,
+ &pTracker->SendBuffer,
+ 0);
+
+ //
+ // the completion routine will get called with the errors and
+ // handle them appropriately, so just return here
+ //
+ return;
+ }
+
+
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+
+ }
+ else
+ {
+
+ // if the remote station does not have a connection to receive the
+ // session pdu on , then we will get back this status. We may also
+ // get this if the destination does not have NBT running at all. This
+ // is a short timeout - 250 milliseconds, times 3.
+ //
+ }
+
+ //
+ // this branch is taken if the TCP connection setup fails or the
+ // tracker has been cancelled.
+ //
+
+ CHECK_PTR(pConnEle);
+
+ pClientIrp = pConnEle->pIrp;
+ pConnEle->pIrp = NULL;
+
+ TrackerCancelled = pTracker->Flags & TRACKER_CANCELLED;
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Startup Continue Failed, State=%X,TrackerFlags=%X pConnEle=%X\n",
+ pConnEle->state,
+ pTracker->Flags,
+ pConnEle));
+
+ //
+ // remove the name from the hash table since we did not connect
+ //
+ //
+ // if it is in the remote table and still active...
+ // and no one else is referencing the name, then delete it from
+ // the hash table.
+ //
+ pNameAddr = pTracker->Connect.pNameAddr;
+ if ((pNameAddr->Verify == REMOTE_NAME) &&
+ (pNameAddr->RefCount == 1) &&
+ (pNameAddr->NameTypeState & STATE_RESOLVED))
+ {
+ NbtDereferenceName(pNameAddr);
+ }
+
+ FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
+
+ if (pConnEle->state != NBT_IDLE)
+ {
+ pConnEle->state = NBT_ASSOCIATED;
+ }
+
+ pLowerConn = pConnEle->pLowerConnId;
+
+ CTESpinFree(pConnEle,OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // Either the connection failed to get setup or the send on the
+ // connection failed, either way, don't mess with disconnects, just
+ // close the connection... If the Tracker was cancelled then it means
+ // someother part of the code has done the disconnect already.
+ //
+ pIrpDisc = NULL;
+ if (TrackerCancelled)
+ {
+ //
+ // Complete the Disconnect Irp that is pending too
+ //
+ pIrpDisc = pConnEle->pIrpDisc;
+ status = STATUS_CANCELLED;
+ }
+
+ // Cache the fact that an attempt to set up a TDI connection failed. This will enable us to
+ // weed out repeated attempts on the same remote address. The only case that is exempt is a
+ // NETBIOS name which we let it pass through because it adopts a different name resolution
+ // mechanism.
+
+ if (pConnEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) {
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT@@@ Will avoid repeated attempts on a nonexistent address\n"));
+ pConnEle->RemoteNameDoesNotExistInDNS = TRUE;
+ }
+
+#ifndef VXD
+ if (status == STATUS_CONNECTION_REFUSED || status == STATUS_IO_TIMEOUT)
+ {
+ status = STATUS_BAD_NETWORK_PATH;
+ }
+#else
+ if (status == TDI_CONN_REFUSED || status == TDI_TIMED_OUT)
+ {
+ status = STATUS_BAD_NETWORK_PATH;
+ }
+#endif
+
+ QueueCleanup(pConnEle);
+
+ //
+ // put back on the idle connection list if nbtcleanupconnection has not
+ // run and taken pconnele off the list (setting the state to Idle).
+ //
+
+ CTESpinLock(pConnEle,OldIrq);
+ if (pConnEle->state != NBT_IDLE)
+ {
+ RelistConnection(pConnEle);
+ }
+ CTESpinFree(pConnEle,OldIrq);
+
+ //
+ // remove the last reference added in nbt connect. The refcount will be 2
+ // if nbtcleanupconnection has not run and 1, if it has. So this call
+ // could free pConnEle.
+ //
+ NbtDereferenceConnection(pConnEle);
+
+
+ // the cancel irp routine in Ntisol.c sets the irp to NULL if it cancels
+ // it.
+ if (pClientIrp)
+ {
+ CTEIoComplete(pClientIrp,status,0L);
+ }
+
+ if (pIrpDisc)
+ {
+ CTEIoComplete(pIrpDisc,STATUS_SUCCESS,0L);
+ }
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SessionStartupCompletion(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo)
+/*++
+Routine Description
+
+ This routine handles the completion of sending the session request pdu.
+ It completes the Irp back to the client indicating the outcome of the
+ transaction if there is an error otherwise it keeps the irp till the
+ session setup response is heard.
+ Tracker block is put back on its free Q and the
+ session header is freed back to the non-paged pool.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ tCONNECTELE *pConnEle;
+ tLOWERCONNECTION *pLowerConn;
+ COMPLETIONCLIENT CompletionRoutine;
+ ULONG state;
+ PCTE_IRP pClientIrp;
+ PCTE_IRP pIrpDisc;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+ pConnEle = (tCONNECTELE *)pTracker->Connect.pConnEle;
+
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pLowerConn = pConnEle->pLowerConnId;
+ //
+ // a failure status means that the transport could not send the
+ // session startup pdu - if this happens, then disconnect the
+ // connection and return the client's irp with the status code
+ //
+
+ if ((!NT_SUCCESS(status)))
+ {
+ // we must check the status first since it is possible that the
+ // lower connection has disappeared already due to a disconnect/cleanup
+ // in the VXD case anyway. Only for a bad status can we be sure
+ // that pConnEle is still valid.
+ //
+ if (pTracker->Connect.pTimer)
+ {
+ StopTimer(pTracker->Connect.pTimer,&CompletionRoutine,NULL);
+ CHECK_PTR(pTracker);
+ pTracker->Connect.pTimer = NULL;
+ }
+ else
+ {
+ CompletionRoutine = NULL;
+ }
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Startup Completion Failed, State=%X,TrackerFlags=%X CompletionRoutine=%X,pConnEle=%X\n",
+ pConnEle->state,
+ pTracker->Flags,
+ CompletionRoutine,
+ pConnEle));
+
+ //
+ // Only if the timer has not expired yet do we kill off the connection
+ // since if the timer has expired, it has already done this in
+ // SessionTimedOut.
+ //
+ if (CompletionRoutine)
+ {
+ CTESpinLock(pConnEle,OldIrq);
+
+ // for some reason sending the session setup pdu failed, so just
+ // close the connection and don't worry about being graceful.
+ //
+ FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
+ pConnEle->pIrpRcv = NULL;
+ state = pConnEle->state;
+ pConnEle->state = NBT_ASSOCIATED;
+
+ pClientIrp = pConnEle->pIrp;
+ CHECK_PTR(pConnEle);
+ pConnEle->pIrp = NULL;
+ pIrpDisc = pConnEle->pIrpDisc;
+ pConnEle->pIrpDisc = NULL;
+ CTESpinFree(pConnEle,OldIrq);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // if the state has changed then some other part of the code
+ // has done the disconnect of the Lower, so don't do it again here.
+ //
+ if (state == NBT_SESSION_OUTBOUND)
+ {
+ QueueCleanup(pConnEle);
+ }
+
+ //
+ // Nbt_idle means that NbtCleanupConnection has run, so do not
+ // relist in this case because the connection is about to be freed.
+ //
+ if (state != NBT_IDLE)
+ {
+ RelistConnection(pConnEle);
+ }
+
+ //
+ // remove the last reference added in nbt connect. The refcount
+ // will be 2 if nbtcleanupconnection has not run and 1, if it has. So this call
+ // could free pConnEle.
+ //
+ NbtDereferenceConnection(pConnEle);
+
+ if (pClientIrp)
+ {
+ CTEIoComplete(pClientIrp,status,0L);
+ }
+ }
+ else
+ {
+ //
+ // the session has probably been cancelled and the Session timeout
+ // routine run, so just clean up the tracker as the final activity,
+ // but be sure the tracker has not already been released in
+ // Outbound.
+ //
+ if (pTracker == (tDGRAM_SEND_TRACKING *)pConnEle->pIrpRcv)
+ {
+ FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
+ // the tracker is stored here during connection setup so
+ // null it out to prevent Outbound from using it.
+ //
+ pConnEle->pIrpRcv = NULL;
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ //
+ // remove the last reference added in nbt connect. The refcount
+ // will be 2 if nbtcleanupconnection has not run and 1, if it has. So this call
+ // could free pConnEle.
+ //
+ NbtDereferenceConnection(pConnEle);
+ }
+
+ }
+ else
+ {
+
+
+
+ //
+ // if OutBound has run, it has set the refcount to zero
+ //
+ if (pTracker->RefConn == 0)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
+ }
+ else
+ {
+ pTracker->RefConn--;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ // remove the reference added in nbt connect
+ NbtDereferenceConnection(pConnEle);
+
+ // NOTE: the last reference done on pConnEle in NbtConnect is NOT undone
+ // until the pLowerConn no longer points to pConnEle!!
+ }
+
+}
+//----------------------------------------------------------------------------
+ VOID
+SessionTimedOut(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine handles timing out a connection setup request. The timer
+ is started when the connection is started and the session setup
+ message is about to be sent.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ tCONNECTELE *pConnEle;
+ tLOWERCONNECTION *pLowerConn;
+ CTE_IRP *pIrp;
+ USHORT State;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ // if pTimerQEntry is null then the timer is being cancelled, so do nothing
+ if (pTimerQEntry)
+ {
+ // kill the connection
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pConnEle = pTracker->Connect.pConnEle;
+ pLowerConn = pConnEle->pLowerConnId;
+ pTracker->Connect.pTimer = NULL;
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Session Timed Out, UpperState=%X,,pConnEle=%X\n",
+ pConnEle->state,pConnEle));
+
+ if (pLowerConn)
+ {
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Session Timed Out, LowerState=%X,TrackerFlags=%X,pLowerConn=%X\n",
+ pLowerConn->State,
+ pLowerConn));
+
+ CTESpinLock(pLowerConn,OldIrq1);
+
+ if ((pConnEle->state == NBT_SESSION_OUTBOUND) &&
+ (pIrp = pConnEle->pIrp))
+ {
+
+ CHECK_PTR(pConnEle);
+ pConnEle->pIrp = NULL;
+
+ State = pConnEle->state;
+ pConnEle->state = NBT_ASSOCIATED;
+
+ CTESpinFree(pLowerConn,OldIrq1);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ QueueCleanup(pConnEle);
+
+ //
+ // Nbt_idle means that nbtcleanupConnection has run and the
+ // connection is about to be deleted, so don't relist.
+ //
+ if (State != NBT_IDLE)
+ {
+ CTESpinLock(pConnEle,OldIrq1);
+ RelistConnection(pConnEle);
+ CTESpinFree(pConnEle,OldIrq1);
+ }
+
+// Don't do this because the transport still must complete the session
+// setup message through SessionStartupCompletion - where the tracker
+// will be freed.
+//
+// FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
+
+ //
+ // Called from NtCancelSession with the Context2 set to
+ // STATUS_CANCELLED when the client IRP is cancelled
+ //
+ if ((ULONG)pContext2 == STATUS_CANCELLED)
+ {
+ status = STATUS_CANCELLED;
+ }
+ else
+ status = STATUS_IO_TIMEOUT;
+
+ CTEIoComplete(pIrp,status,0);
+ }
+ else
+ {
+
+ CTESpinFree(pLowerConn,OldIrq1);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+RelistConnection(
+ IN tCONNECTELE *pConnEle
+ )
+/*++
+
+Routine Description
+
+ This routine unlinks the ConnEle from the ConnectActive list and puts it
+ back on the Connecthead. It is used when a connection goes to
+ NBT_ASSOCIATED state.
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(pConnEle->pClientEle,OldIrq);
+ //
+ // if the state is NBT_IDLE it means that NbtCleanupConnection has run
+ // and removed the connection from its list in preparation for
+ // freeing the memory, so don't put it back on the list
+ //
+ if (pConnEle->state != NBT_IDLE)
+ {
+ pConnEle->state = NBT_ASSOCIATED;
+ RemoveEntryList(&pConnEle->Linkage);
+ InsertTailList(&pConnEle->pClientEle->ConnectHead,&pConnEle->Linkage);
+ }
+ CTESpinFree(pConnEle->pClientEle,OldIrq);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtSend(
+ IN TDI_REQUEST *pRequest,
+ IN USHORT Flags,
+ IN ULONG SendLength,
+ OUT LONG *pSentLength,
+ IN PVOID *pBuffer,
+ IN tDEVICECONTEXT *pContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description
+
+ ... does nothing now....
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ //
+ // This routine is never hit since the NTISOL.C routine NTSEND actually
+ // bypasses this code and passes the send directly to the transport
+ //
+ ASSERT(0);
+
+ return(STATUS_SUCCESS);
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtListen(
+ IN TDI_REQUEST *pRequest,
+ IN ULONG Flags,
+ IN TDI_CONNECTION_INFORMATION *pRequestConnectInfo,
+ OUT TDI_CONNECTION_INFORMATION *pReturnConnectInfo,
+ IN PVOID pIrp)
+
+/*++
+Routine Description:
+
+ This Routine posts a listen on an open connection allowing a client to
+ indicate that is prepared to accept inbound connections. The ConnectInfo
+ may contain an address to specify which remote clients may connect to
+ the connection although we don't currently look at that info.
+
+Arguments:
+
+
+Return Value:
+
+ ReturnConnectInfo - status of the request
+
+--*/
+
+{
+ tCLIENTELE *pClientEle;
+ tCONNECTELE *pConnEle;
+ NTSTATUS status;
+ tLISTENREQUESTS *pListenReq;
+ CTELockHandle OldIrq;
+
+ // now find the connection object to link this listen record to
+ pConnEle = ((tCONNECTELE *)pRequest->Handle.ConnectionContext);
+
+ // be sure we have not been passed some bogus ptr
+ //
+ CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status);
+
+ //
+ // Find the client record associated with this connection
+ //
+ if (pConnEle->state != NBT_ASSOCIATED)
+ {
+ return(STATUS_INVALID_HANDLE);
+ }
+
+ pClientEle = (tCLIENTELE *)pConnEle->pClientEle;
+
+ pListenReq = NbtAllocMem(sizeof(tLISTENREQUESTS),NBT_TAG('I'));
+
+ if (!pListenReq)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // Fill in the Listen request
+ //
+
+ pListenReq->pIrp = pIrp;
+ pListenReq->Flags = Flags;
+ pListenReq->pConnectEle = pConnEle;
+ pListenReq->pConnInfo = pRequestConnectInfo;
+ pListenReq->pReturnConnInfo = pReturnConnectInfo;
+ pListenReq->CompletionRoutine = pRequest->RequestNotifyObject;
+ pListenReq->Context = pRequest->RequestContext;
+
+ CTESpinLock(pClientEle,OldIrq);
+
+ // queue the listen request on the client object
+ InsertTailList(&pClientEle->ListenHead,&pListenReq->Linkage);
+
+ status = NTCheckSetCancelRoutine(pIrp,(PVOID)NbtCancelListen,0);
+
+ if (!NT_SUCCESS(status))
+ {
+ RemoveEntryList(&pListenReq->Linkage);
+ status = STATUS_CANCELLED;
+ }
+ else
+ status = STATUS_PENDING;
+
+ CTESpinFree(pClientEle,OldIrq);
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtDisconnect(
+ IN TDI_REQUEST *pRequest,
+ IN PVOID pTimeout,
+ IN ULONG Flags,
+ IN PTDI_CONNECTION_INFORMATION pCallInfo,
+ IN PTDI_CONNECTION_INFORMATION pReturnInfo,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles taking down a connection (netbios session).
+
+Arguments:
+
+
+Return Value:
+
+ TDI_STATUS - status of the request
+
+--*/
+
+{
+ tCONNECTELE *pConnEle;
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq2;
+ CTELockHandle OldIrq3;
+ tLOWERCONNECTION *pLowerConn;
+ ULONG LowerState = NBT_IDLE;
+ ULONG StateRcv;
+ BOOLEAN Originator = TRUE;
+ PCTE_IRP pClientIrp = NULL;
+ BOOLEAN RelistIt = FALSE;
+ BOOLEAN Wait;
+
+ pConnEle = pRequest->Handle.ConnectionContext;
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:NbtDisconnect Hit,state %X %X\n",pConnEle->state,pConnEle));
+
+ // check the connection element for validity
+ //CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status)
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if ((pConnEle->state <= NBT_ASSOCIATED) ||
+ (pConnEle->state >= NBT_DISCONNECTING))
+ {
+ // the connection is not connected so reject the disconnect attempt
+ // ( with an Invalid Connection return code ) - unless there is a
+ // value stored in the flag
+ // DiscFlag field which will be the status of a previous
+ // disconnect indication from the transport.
+ //
+// if ((Flags == TDI_DISCONNECT_WAIT) && (pConnEle->DiscFlag))
+ if ((pConnEle->DiscFlag))
+ {
+ if (Flags == TDI_DISCONNECT_WAIT)
+ {
+ if (pConnEle->DiscFlag == TDI_DISCONNECT_ABORT)
+ {
+ status = STATUS_CONNECTION_RESET;
+ }
+ else
+ {
+ status = STATUS_GRACEFUL_DISCONNECT;
+ }
+ }
+ else
+ {
+ status = STATUS_SUCCESS;
+ }
+
+ // clear the flag now.
+ CHECK_PTR(pConnEle);
+ pConnEle->DiscFlag = 0;
+ }
+ else
+ {
+ status = STATUS_CONNECTION_INVALID;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return(status);
+ }
+
+ // to link and unlink upper and lower connections the Joint lock must
+ // be held. This allows coordination from the lower side and from
+ // the upper side. - i.e. once the joint lock is held, the upper and lower
+ // connections cannot become unlinked.
+ //
+ CTESpinLock(pConnEle,OldIrq2);
+
+ // Do this check with the spin lock held to avoid a race condition
+ // with a disconnect coming in from the transport at the same time.
+ //
+
+ pLowerConn = pConnEle->pLowerConnId;
+
+ //
+ // a disconnect wait is not really a disconnect, it is just there so that
+ // when a disconnect occurs, the transport will complete it, and indicate
+ // to the client there is a disconnect (instead of having a disconnect
+ // indication handler) - therefore, for Disc Wait, do NOT change state.
+ //
+ CHECK_PTR(pConnEle);
+ pConnEle->pIrpDisc = NULL;
+ if (Flags == TDI_DISCONNECT_WAIT)
+ {
+
+ //
+ // save the Irp here and wait for a disconnect to return it
+ // to the client.
+ //
+ if (pConnEle->state == NBT_SESSION_UP)
+ {
+ pConnEle->pIrpClose = pIrp;
+ status = STATUS_PENDING;
+
+ //
+ // call this routine to check if the cancel flag has been
+ // already set and therefore we must return the irp now
+ //
+ status = NTSetCancelRoutine(pIrp,DiscWaitCancel,pLowerConn->pDeviceContext);
+ //
+ // change the ret status so if the irp has been cancelled,
+ // driver.c will not also return it, since NTSetCancelRoutine
+ // will call the cancel routine and return the irp.
+ //
+ status = STATUS_PENDING;
+ }
+ else
+ {
+ status = STATUS_CONNECTION_INVALID;
+ }
+
+
+ CTESpinFree(pConnEle,OldIrq2);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return(status);
+
+ }
+ else
+ {
+ if (pLowerConn)
+ {
+
+
+ if (pConnEle->state > NBT_ASSOCIATED)
+ {
+ ULONG state = pConnEle->state;
+ tDGRAM_SEND_TRACKING *pTracker;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pConnEle->pIrpRcv;
+
+ switch (state)
+ {
+ case NBT_RECONNECTING:
+ //
+ // the connection is waiting on the Exworker Q to run
+ // nbtreconnect. When that runs the connect irp is
+ // returned.
+ //
+ pTracker->Flags |= TRACKER_CANCELLED;
+
+ CTESpinFree(pConnEle,OldIrq2);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ CTESpinLock(pConnEle,OldIrq);
+ FreeRcvBuffers(pConnEle,&OldIrq);
+ CTESpinFree(pConnEle,OldIrq);
+
+ return(STATUS_SUCCESS);
+
+ case NBT_SESSION_OUTBOUND:
+ {
+ tTIMERQENTRY *pTimerEntry;
+
+ LOCATION(0x66)
+ if (pTimerEntry = pTracker->Connect.pTimer)
+ {
+ COMPLETIONCLIENT ClientRoutine;
+ PVOID pContext;
+
+ //
+ // the Session Setup Message has been sent
+ // so stop the SessionSetup Timer.
+ //
+ LOCATION(0x67)
+ CHECK_PTR(pTracker);
+ pTracker->Connect.pTimer = NULL;
+ CTESpinFree(pConnEle,OldIrq2);
+
+ StopTimer(pTimerEntry,&ClientRoutine,&pContext);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ if (ClientRoutine)
+ {
+ (*(COMPLETIONROUTINE)ClientRoutine)(pContext,NULL,pTimerEntry);
+ }
+ // else...
+ // the timer has completed and called QueueCleanup
+ // so all we need to do is return here.
+
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ ASSERTMSG("Nbt:In outbound state, but no timer.../n",0);
+ pTracker->Flags |= TRACKER_CANCELLED;
+ CTESpinFree(pConnEle,OldIrq2);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return(STATUS_SUCCESS);
+ }
+
+ break;
+
+ }
+
+ case NBT_CONNECTING:
+
+ //
+ // This searchs for timers outstanding on name queries
+ // and name queries held up on Lmhosts or Dns Qs
+ //
+ LOCATION(0x69)
+ status = CleanupConnectingState(pConnEle,pLowerConn->pDeviceContext,
+ &OldIrq2,&OldIrq);
+
+ if (status == STATUS_UNSUCCESSFUL)
+ {
+ LOCATION(0x6A)
+ //
+ // set this flag to tell sessionsetupcontinue or
+ // SessionStartupContinue not to process
+ // anything, except to free the tracker
+ //
+ pTracker->Flags = TRACKER_CANCELLED;
+
+ //
+ // failed to cancel the name query so do not deref
+ // pConnEle yet.
+ //
+ //
+ // hold on to disconnect irp here - till name query is done
+ // then complete both the connect and disconnect irp
+ //
+ pConnEle->pIrpDisc = pIrp;
+
+ status = STATUS_PENDING;
+ }
+ else
+ if (status == STATUS_PENDING)
+ {
+ LOCATION(0x6B)
+ // the connection is being setup with the transport
+ // so disconnect below
+ //
+
+ pTracker->Flags = TRACKER_CANCELLED;
+ //
+ // CleanupAfterDisconnect expects this ref count
+ // to be 2, meaning that it got connected, so increment
+ // here
+ pLowerConn->RefCount++;
+ break;
+ }
+
+ CTESpinFree(pConnEle,OldIrq2);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+
+ return(status);
+
+ break;
+ }
+
+ CTESpinLock(pLowerConn,OldIrq3);
+
+ if (pConnEle->state != NBT_SESSION_UP)
+ { //
+ // do an abortive disconnect to be sure it completes now.
+ //
+ Flags = TDI_DISCONNECT_ABORT;
+ PUSH_LOCATION(0xA1);
+ }
+
+ LOCATION(0x6C)
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:LowerConn,state %X,Src %X %X\n",
+ pLowerConn->State,pLowerConn->SrcIpAddr,pLowerConn));
+
+ ASSERT(pConnEle->RefCount > 1);
+
+ Originator = pLowerConn->bOriginator;
+
+ //
+ // the upper connection is going to be put back on its free
+ // list, and the lower one is going to get a Disconnect
+ // request, so put the upper back in associated, and separate
+ // the upper and lower connections
+ //
+ pConnEle->state = NBT_ASSOCIATED;
+ CHECK_PTR(pConnEle);
+ pConnEle->pLowerConnId = NULL;
+
+ CHECK_PTR(pLowerConn);
+ pLowerConn->pUpperConnection = NULL;
+ LowerState = pLowerConn->State;
+ StateRcv = pLowerConn->StateRcv;
+
+//
+// if we had a connection in partial rcv state, make sure to remove it from
+// the list
+//
+#ifdef VXD
+ if ( pLowerConn->StateRcv == PARTIAL_RCV &&
+ (pLowerConn->fOnPartialRcvList == TRUE) )
+ {
+ RemoveEntryList( &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+ }
+#endif
+
+ pLowerConn->State = NBT_DISCONNECTING;
+
+ SetStateProc( pLowerConn, RejectAnyData ) ;
+
+ if (!pConnEle->pIrpDisc)
+ {
+ pLowerConn->pIrp = pIrp ;
+ }
+
+ CTESpinFree(pLowerConn,OldIrq3);
+
+ PUSH_LOCATION(0x84);
+ CTESpinFree(pConnEle,OldIrq2);
+
+ // remove the reference added to pConnEle when pLowerConn pointed
+ // to it, since that pointer link was just removed.
+ // if the state is not disconnecting...
+ //
+ DereferenceIfNotInRcvHandler(pConnEle,pLowerConn);
+
+ RelistIt = TRUE;
+ }
+ else
+ {
+ LOCATION(0x6D)
+ PUSH_LOCATION(0x83);
+ CHECK_PTR(pConnEle);
+ CHECK_PTR(pLowerConn);
+ pLowerConn->pUpperConnection = NULL;
+ pConnEle->pLowerConnId = NULL;
+ StateRcv = NORMAL;
+
+ CTESpinFree(pConnEle,OldIrq2);
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // check for any RcvIrp that may be still around
+ //
+ CTESpinLock(pLowerConn,OldIrq);
+ if (StateRcv == FILL_IRP)
+ {
+ if (pConnEle->pIrpRcv)
+ {
+ PCTE_IRP pIrp;
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Cancelling RcvIrp on Disconnect!!!\n"));
+ pIrp = pConnEle->pIrpRcv;
+ CHECK_PTR(pConnEle);
+ pConnEle->pIrpRcv = NULL;
+
+ CTESpinFree(pLowerConn,OldIrq);
+ #ifndef VXD
+ IoCancelIrp(pIrp);
+ #else
+ CTEIoComplete(pIrp,STATUS_CANCELLED,0);
+ #endif
+
+ CHECK_PTR(pConnEle);
+ pConnEle->pIrpRcv = NULL;
+ }
+ else
+ CTESpinFree(pLowerConn,OldIrq);
+
+ //
+ // when the disconnect irp is returned we will close the connection
+ // to avoid any peculiarities. This also lets the other side
+ // know that we did not get all the data.
+ //
+ Flags = TDI_DISCONNECT_ABORT;
+ }
+ else
+ CTESpinFree(pLowerConn,OldIrq);
+
+ //
+ // check if there is still data waiting in the transport for this end point
+ // and if so do an abortive disconnect to let the other side know that something
+ // went wrong
+ //
+ if (pConnEle->BytesInXport)
+ {
+ PUSH_LOCATION(0xA0);
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Doing ABORTIVE disconnect, dataInXport = %X\n",
+ pConnEle->BytesInXport));
+ Flags = TDI_DISCONNECT_ABORT;
+ }
+
+
+ }
+ else
+ {
+ CTESpinFree(pConnEle,OldIrq2);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ }
+ }
+
+ ASSERT(pConnEle->RefCount > 0);
+
+ CTESpinLock(pConnEle,OldIrq);
+ FreeRcvBuffers(pConnEle,&OldIrq);
+ CTESpinFree(pConnEle,OldIrq);
+
+ if (RelistIt)
+ {
+ //
+ // put the upper connection back on its free list
+ //
+ RelistConnection(pConnEle);
+ }
+
+ //
+ // disconnect (and delete) the lower connection
+ //
+ // when nbtdisconnect is called from cleanup connection it does not
+ // have an irp and it wants a synchronous disconnect, so set wait
+ // to true in this case
+ //
+ if (!pIrp)
+ {
+ Wait = TRUE;
+ }
+ else
+ Wait = FALSE;
+
+ status = DisconnectLower(pLowerConn,LowerState,Flags,pTimeout,Wait);
+
+ if ((pConnEle->pIrpDisc) &&
+ (status != STATUS_INSUFFICIENT_RESOURCES))
+ {
+ // don't complete the disconnect irp yet if we are holding onto
+ // it
+ status = STATUS_PENDING;
+ }
+
+ return(status);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+DisconnectLower(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG state,
+ IN ULONG Flags,
+ IN PVOID Timeout,
+ IN BOOLEAN Wait
+ )
+
+/*++
+Routine Description:
+
+ This Routine handles disconnecting the lower half of a connection.
+
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status=STATUS_SUCCESS;
+ tDGRAM_SEND_TRACKING *pTracker;
+
+ if (pLowerConn)
+ {
+ //
+ // no need to disconnect a connection in the connecting state since it
+ // hasn't connected yet...i.e. one where the destination refuses to
+ // accept the tcp connection.... hmmmm maybe we do need to disconnect
+ // a connection in the connecting state, since the transport is
+ // actively trying to connect the connection, and we need to stop
+ // that activity - so the Upper connection is connecting during
+ // name resolution, but the lower one isn't connecting until the
+ // tcp connection phase begins.
+ //
+ if ((state <= NBT_SESSION_UP) &&
+ (state >= NBT_CONNECTING))
+ {
+
+ //
+ // got a cleanup for an active connection, so send a disconnect down
+ // to the transport
+ //
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt waiting for disconnect...\n"));
+
+ status = GetTracker(&pTracker);
+ if (NT_SUCCESS(status))
+ {
+ ULONG TimeVal;
+
+ // this should return status pending and the irp will be completed
+ // in CleanupAfterDisconnect in hndlrs.c
+ pTracker->Connect.pConnEle = (PVOID)pLowerConn;
+#if DBG
+ if (Timeout)
+ {
+ TimeVal = ((PTIME)Timeout)->LowTime;
+ }
+ else
+ TimeVal = 0;
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Disconnect Timout = %X,Flags=%X\n",
+ TimeVal,Flags));
+#endif
+
+ // in the case where CleanupAddress calls cleanupConnection
+ // which calls nbtdisconnect, we do not have an irp to wait
+ // on so pass a flag down to TdiDisconnect to do a synchronous
+ // disconnect.
+ //
+ status = TcpDisconnect(pTracker,Timeout,Flags,Wait);
+
+#ifndef VXD
+ if (Wait)
+ {
+ // we need to call disconnect done now
+ // to free the tracker and cleanup the connection
+ //
+ DisconnectDone(pTracker,STATUS_SUCCESS,0);
+ }
+#else
+ //
+ // if the disconnect is abortive, transport doesn't call us
+ // back so let's call DisconnectDone so that the lowerconn gets
+ // cleaned up properly! (Wait parm is of no use in vxd)
+ //
+ if (Flags == TDI_DISCONNECT_ABORT)
+ {
+ // we need to call disconnect done now
+ // to free the tracker and cleanup the connection
+ //
+ DisconnectDone(pTracker,STATUS_SUCCESS,0);
+ }
+#endif
+ }
+ else
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ }
+
+ return status ;
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtAccept(
+ TDI_REQUEST *pRequest,
+ IN TDI_CONNECTION_INFORMATION *pAcceptInfo,
+ OUT TDI_CONNECTION_INFORMATION *pReturnAcceptInfo,
+ IN PIRP pIrp)
+
+/*++
+
+Routine Description
+
+ This routine handles accepting an inbound connection by a client.
+ The client calls this routine after it has been alerted
+ by a Listen completing back to the client.
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ tCONNECTELE *pConnectEle;
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+
+ // get the client object associated with this connection
+ pConnectEle = (tCONNECTELE *)pRequest->Handle.ConnectionContext;
+
+ CTEVerifyHandle(pConnectEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status);
+
+ //
+ // a Listen has completed
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CTESpinLockAtDpc(pConnectEle);
+ if (pConnectEle->state == NBT_SESSION_WAITACCEPT)
+ {
+ tLOWERCONNECTION *pLowerConn;
+
+ //
+ // We need to send a session response PDU here, since a Listen has
+ // has completed back to the client, and the session is not yet up
+ //
+ pConnectEle->state = NBT_SESSION_UP;
+
+ pLowerConn = (tLOWERCONNECTION *)pConnectEle->pLowerConnId;
+ pLowerConn->State = NBT_SESSION_UP;
+ pLowerConn->StateRcv = NORMAL;
+ SetStateProc( pLowerConn, Normal ) ;
+
+ CTESpinFreeAtDpc(pConnectEle);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ status = TcpSendSessionResponse(
+ pLowerConn,
+ NBT_POSITIVE_SESSION_RESPONSE,
+ 0L);
+
+ if (NT_SUCCESS(status))
+ {
+ status = STATUS_SUCCESS;
+ }
+
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ CTESpinFreeAtDpc(pConnectEle);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtReceiveDatagram(
+ IN TDI_REQUEST *pRequest,
+ IN PTDI_CONNECTION_INFORMATION pReceiveInfo,
+ IN PTDI_CONNECTION_INFORMATION pReturnedInfo,
+ IN LONG ReceiveLength,
+ IN LONG *pReceivedLength,
+ IN PVOID pBuffer,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description
+
+ This routine handles sending client data to the Transport TDI
+ interface. It is mostly a pass through routine for the data
+ except that this code must create a datagram header and pass that
+ header back to the calling routine.
+
+Arguments:
+
+
+Return Values:
+
+ NTSTATUS - status of the request
+
+--*/
+{
+
+ NTSTATUS status;
+ tCLIENTELE *pClientEle;
+ CTELockHandle OldIrq;
+ tRCVELE *pRcvEle;
+ tADDRESSELE *pAddressEle;
+
+
+ pClientEle = (tCLIENTELE *)pRequest->Handle.AddressHandle;
+ CTEVerifyHandle(pClientEle,NBT_VERIFY_CLIENT,tCLIENTELE,&status);
+
+ pAddressEle = pClientEle->pAddress;
+
+ pRcvEle = (tRCVELE *)NbtAllocMem(sizeof(tRCVELE),NBT_TAG('J'));
+ if (!pRcvEle)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pRcvEle->pIrp = pIrp;
+ pRcvEle->ReceiveInfo = pReceiveInfo;
+ pRcvEle->ReturnedInfo = pReturnedInfo;
+ pRcvEle->RcvLength = ReceiveLength;
+ pRcvEle->pRcvBuffer = pBuffer;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ //
+ // tack the receive on to the client element for later use
+ //
+ InsertTailList(&pClientEle->RcvDgramHead,&pRcvEle->Linkage);
+
+ status = NTCheckSetCancelRoutine(pIrp,(PVOID)NTCancelRcvDgram,pDeviceContext);
+ if (!NT_SUCCESS(status))
+ {
+ RemoveEntryList(&pRcvEle->Linkage);
+ }
+ else
+ status = STATUS_PENDING;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:RcvDgram posted (pIrp) %X \n",pIrp));
+
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+FindNameOrQuery(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PUCHAR pName,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID QueryCompletion,
+ IN tDGRAM_SEND_TRACKING **ppTracker,
+ IN BOOLEAN DgramSend,
+ OUT tNAMEADDR **ppNameAddr
+
+ )
+/*++
+
+Routine Description
+
+ This routine handles finding a name in the local or remote table or doing
+ a name query on the network.
+
+Arguments:
+
+
+Return Values:
+
+ NTSTATUS - status of the request
+
+--*/
+{
+
+ tNAMEADDR *pNameAddr;
+ CTELockHandle OldIrq2;
+ NTSTATUS status=STATUS_UNSUCCESSFUL;
+
+
+ //
+ // this saves the client threads security context so we can
+ // open remote lmhost files later.- it is outside the Spin locks
+ // so it can be pageable
+ //
+ CTESaveClientSecurity(pTracker);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq2);
+
+ if (ppTracker)
+ {
+ *ppTracker = NULL;
+ }
+
+ // send to the NetBios Broadcast name, so use the subnet broadcast
+ // address - also - a
+ // Kludge to keep the browser happy - always broadcast sends to
+ // 1d, however NodeStatus's are sent to the node owning the 1d name now.
+ //
+ if (((pName[0] == '*') || ((pName[NETBIOS_NAME_SIZE-1] == 0x1d)) && DgramSend))
+ {
+ // this 'fake' pNameAddr has to be setup carefully so that the memory
+ // is released when NbtDeferenceName is called from SendDgramCompletion
+ // Note that this code does not apply to NbtConnect since these names
+ // are group names, and NbtConnect will not allow a session to a group
+ // name.
+ status = STATUS_INSUFFICIENT_RESOURCES ;
+ pNameAddr = NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('K'));
+
+ if (pNameAddr)
+ {
+ CTEZeroMemory(pNameAddr,sizeof(tNAMEADDR));
+ CTEMemCopy( pNameAddr->Name, pName, NETBIOS_NAME_SIZE ) ;
+ pNameAddr->IpAddress = pDeviceContext->BroadcastAddress;
+ pNameAddr->NameTypeState = NAMETYPE_GROUP | STATE_RESOLVED;
+
+ // gets incremented below, and decremented when NbtDereferenceName
+ // is called
+ CHECK_PTR(pNameAddr);
+ pNameAddr->RefCount = 0;
+ pNameAddr->Verify = LOCAL_NAME;
+ pNameAddr->AdapterMask = (CTEULONGLONG)-1;
+
+ // adjust the linked list ptr to fool the RemoveEntry routine
+ // so it does not do anything wierd in NbtDeferenceName
+ //
+ pNameAddr->Linkage.Flink = pNameAddr->Linkage.Blink = &pNameAddr->Linkage;
+
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+ DELETE_CLIENT_SECURITY(pTracker);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ }
+ else
+ {
+ // The pdu is all made up and ready to go except that we don't know
+ // the destination IP address yet, so check in the local then remote
+ // table for the ip address.
+ //
+ pNameAddr = NULL;
+
+ //
+ // Dont check local cache for 1C names, to force a WINS query; so we find other
+ // DCs even if we have a local DC running.
+ //
+ if ((pName[NETBIOS_NAME_SIZE-1] != 0x1c) )
+ {
+ status = FindInHashTable(NbtConfig.pLocalHashTbl,
+ pName,
+ NbtConfig.pScope,
+ &pNameAddr);
+ } else {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ // check the remote table now if not found, or if it was found in
+ // conflict in the local table, or if it was found and its a group name
+ // or if it was found to be resolving in the local table. When the
+ // remote query timesout, it will check the local again to see if
+ // it is resolved yet.
+ // Going to the remote table for group names
+ // allows special Internet group names to be registered as
+ // as group names in the local table and still prompt this code to go
+ // to the name server to check for an internet group name. Bnodes do
+ // not understand internet group names as being different from
+ // regular group names, - they just broadcast to both. (Note: this
+ // allows Bnodes to resolve group names in the local table and do
+ // a broadcast to them without a costly broadcast name query for a
+ // group name (where everyone responds)). Node Status uses this routine too
+ // and it always wants to find the singular address of the destination,
+ // since it doesn't make sense doing a node status to the broadcast
+ // address.
+ // DgramSend is a flag to differentiate Connect attempts from datagram
+ // send attempts, so the last part of the If says that if it is a
+ // group name and not a Bnode, and not a Dgram Send, then check the
+ // remote table.
+ //
+ if ((!NT_SUCCESS(status)) || (pNameAddr->NameTypeState & STATE_CONFLICT) ||
+ (pNameAddr->NameTypeState & STATE_RESOLVING) ||
+ (((pNameAddr->NameTypeState & (NAMETYPE_GROUP | NAMETYPE_INET_GROUP))&&
+ !(NodeType & BNODE)) && !DgramSend))
+ {
+ pNameAddr = NULL;
+ status = FindInHashTable(NbtConfig.pRemoteHashTbl,
+ pName,
+ NbtConfig.pScope,
+ &pNameAddr);
+ }
+ }
+
+ // The proxy puts name in the released state, so we need to ignore those
+ // and do another name query
+ // If the name is not resolved on this adapter then do a name query.
+ //
+ if (!NT_SUCCESS(status) || (pNameAddr->NameTypeState & STATE_RELEASED) ||
+ (NT_SUCCESS(status)
+ && (!(pNameAddr->AdapterMask & pDeviceContext->AdapterNumber))) )
+ {
+ // remove the released name from the name table since we will
+ // re-resolve it. This is needed in the proxy case where it leaves
+ // names in the released state in the hash table as a negative
+ // cache.
+ //
+ if (NT_SUCCESS(status) && (pNameAddr->NameTypeState & STATE_RELEASED) &&
+ (pNameAddr->RefCount == 1))
+ {
+ NbtDereferenceName(pNameAddr);
+ }
+
+ // fill in some tracking values so we can complete the send later
+ InitializeListHead(&pTracker->TrackerList);
+
+ // this will query the name on the network and call a routine to
+ // finish sending the datagram when the query completes.
+ status = QueryNameOnNet(
+ pName,
+ NbtConfig.pScope,
+ 0, //no ip address yet.
+ NBT_UNIQUE, //use this as the default
+ (PVOID)pTracker,
+ QueryCompletion,
+ NodeType & NODE_MASK,
+ NULL,
+ pDeviceContext,
+ ppTracker,
+ &OldIrq2);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+ }
+ else
+ {
+ // check the name state and if resolved, send to it
+ if (pNameAddr->NameTypeState & STATE_RESOLVED)
+ {
+ //
+ // found the name in the remote hash table, so send to it
+ //
+
+ // increment refcount so the name does not disappear out from under us
+ pNameAddr->RefCount++;
+ //
+ // Incase this name is next in line to be purged from the cache,
+ // bump the timeoutcount back up so it will stick around.
+ //
+ pNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
+
+ //
+ // check if it is a 1C name and if there is a name in
+ // the domainname list
+ //
+ if ( pTracker->pDestName[NETBIOS_NAME_SIZE-1] == 0x1c
+
+ )
+ {
+ tNAMEADDR *pNameHdr;
+
+ //
+ // If the 1CNameAddr field is NULL here, we overwrite the pConnEle element (which is
+ // a union in the tracker). We check for NULL here and fail the request.
+ //
+ if (pNameHdr = FindInDomainList(pTracker->pDestName,&DomainNames.DomainList)) {
+ pTracker->p1CNameAddr = pNameHdr;
+ pTracker->p1CNameAddr->RefCount++;
+ } else {
+ pTracker->p1CNameAddr = NULL;
+
+ //
+ // Fail all connect attempts to 1C names.
+ //
+ if (pTracker->Flags & SESSION_SETUP_FLAG) {
+ KdPrint(("Session setup: p1CNameAddr was NULL\n"));
+#if DBG
+ if (NodeType & BNODE) {
+ ASSERT(FALSE);
+ }
+#endif
+ status = STATUS_UNEXPECTED_NETWORK_ERROR;
+ }
+ }
+
+ }
+
+ //
+ // overwrite the pDestName field with the pNameAddr value
+ // so that SendDgramContinue can send to Internet group names
+ //
+ pTracker->pNameAddr = pNameAddr;
+ *ppNameAddr = pNameAddr;
+
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+ }
+ else
+ if (pNameAddr->NameTypeState & STATE_RESOLVING)
+ {
+
+ ASSERTMSG("A resolving name in the name table!",0);
+
+ status = SendToResolvingName(pNameAddr,
+ pName,
+ OldIrq2,
+ pTracker,
+ QueryCompletion);
+
+ }
+ else
+ {
+ //
+ // Name neither in the RESOLVED nor RESOLVING state
+ //
+ NBT_PROXY_DBG(("NbtSendDatagram: STATE of NAME %16.16s(%X) is %d\n", pName, pName[15], pNameAddr->NameTypeState & NAME_STATE_MASK));
+ status = STATUS_UNEXPECTED_NETWORK_ERROR;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+ }
+
+ }
+
+ if (status != STATUS_PENDING)
+ {
+ DELETE_CLIENT_SECURITY(pTracker);
+ }
+ return(status);
+}
+//----------------------------------------------------------------------------
+ tNAMEADDR *
+FindNameRemoteThenLocal(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ OUT PULONG plNameType
+ )
+/*++
+
+Routine Description
+
+ This routine Queries the remote hash table then the local one for a name.
+
+Arguments:
+
+Return Values:
+
+ NTSTATUS - completion status
+
+--*/
+{
+ tNAMEADDR *pNameAddr;
+
+ pNameAddr = FindName(
+ NBT_REMOTE,
+ pTracker->Connect.pDestName,
+ NbtConfig.pScope,
+ (PUSHORT)plNameType);
+ if (!pNameAddr)
+ {
+ pNameAddr = FindName(
+ NBT_LOCAL,
+ pTracker->Connect.pDestName,
+ NbtConfig.pScope,
+ (PUSHORT)plNameType);
+ }
+ else
+ if (pNameAddr->AdapterMask & pTracker->pDeviceContext->AdapterNumber)
+ {
+ // only if the name is resolved on this adapter, return it...
+ pNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
+ }
+ else
+ {
+ pNameAddr = NULL;
+ }
+
+ return(pNameAddr);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+SendToResolvingName(
+ IN tNAMEADDR *pNameAddr,
+ IN PCHAR pName,
+ IN CTELockHandle OldIrq,
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PVOID QueryCompletion
+ )
+/*++
+
+Routine Description
+
+ This routine handles the situation where a session send or a datagram send
+ is made WHILE the name is still resolving. The idea here is to hook this
+ tracker on to the one already doing the name query and when the first completes
+ this tracker will be completed too.
+
+Arguments:
+
+Return Values:
+
+ NTSTATUS - completion status
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTrack;
+
+
+ KdPrint(("Nbt:Two Name Queries for the same Resolving name %15.15s <%X>\n",
+ pNameAddr->Name,pNameAddr->Name[NETBIOS_NAME_SIZE-1]));
+
+#ifdef PROXY_NODE
+ //
+ // Check if the query outstanding was sent by the PROXY code.
+ // If yes, we stop the timer and send the query ourselves.
+ //
+ if (pNameAddr->fProxyReq)
+ {
+ NTSTATUS status;
+ //
+ // Stop the proxy timer. This will result in
+ // cleanup of the tracker buffer
+ //
+ NBT_PROXY_DBG(("NbtSendDatagram: STOPPING PROXY TIMER FOR NAME %16.16s(%X)\n", pName, pName[15]));
+
+ // **** TODO ****** the name may be resolving with LMhosts or
+ // DNS so we can't just stop the timer and carry on!!!.
+ //
+ status = StopTimer( pNameAddr->pTimer,NULL,NULL);
+
+ CHECK_PTR(pNameAddr);
+ pNameAddr->pTimer = NULL;
+
+ pNameAddr->NameTypeState = STATE_RELEASED;
+
+ //
+ // this will query the name on the network and call a
+ // routine to finish sending the datagram when the query
+ // completes.
+ //
+ status = QueryNameOnNet(
+ pName,
+ NbtConfig.pScope,
+ 0, //no ip address yet.
+ NBT_UNIQUE, //use this as the default
+ (PVOID)pTracker,
+ QueryCompletion,
+ NodeType & NODE_MASK,
+ pNameAddr,
+ pTracker->pDeviceContext,
+ NULL,
+ &OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return(status);
+
+ //
+ // NOTE: QueryNameOnNet frees the pNameAddr by calling NbtDereferenceName
+ // if that routine fails for some reason.
+ //
+
+ }
+ else
+#endif
+ {
+ ASSERT(pNameAddr->pTracker);
+
+ // there is currently a name query outstanding so just hook
+ // our tracker to the tracker already there.. use the
+ // list entry TrackerList for this.
+ //
+
+ //pTrack = (tDGRAM_SEND_TRACKING *)pNameAddr->pTimer->ClientContext;
+
+ pTrack = pNameAddr->pTracker;
+ //
+ // save the completion routine for this tracker since it may
+ // be different than the tracker currently doing the query
+ //
+ pTracker->CompletionRoutine = QueryCompletion;
+
+ InsertTailList(&pTrack->TrackerList,&pTracker->TrackerList);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+
+ // we don't want to complete the Irp, so return pending status
+ //
+ return(STATUS_PENDING);
+ }
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtSendDatagram(
+ IN TDI_REQUEST *pRequest,
+ IN PTDI_CONNECTION_INFORMATION pSendInfo,
+ IN LONG SendLength,
+ IN LONG *pSentLength,
+ IN PVOID pBuffer,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description
+
+ This routine handles sending client data to the Transport TDI
+ interface. It is mostly a pass through routine for the data
+ except that this code must create a datagram header and pass that
+ header back to the calling routine.
+
+Arguments:
+
+
+Return Values:
+
+ NTSTATUS - status of the request
+
+--*/
+{
+
+ tCLIENTELE *pClientEle;
+ tDGRAMHDR *pDgramHdr;
+ NTSTATUS status;
+ ULONG lNameType;
+ tNAMEADDR *pNameAddr;
+ tDGRAM_SEND_TRACKING *pTracker;
+ PCHAR pName,pSourceName;
+ ULONG NameLen;
+ LONG NameType;
+ ULONG SendCount;
+
+
+ CTEPagedCode();
+
+ // If there is no ip address configured, pretend that the datagram
+ // send succeeded.
+ //
+ if ((pDeviceContext->IpAddress == 0) ||
+ (pDeviceContext->pDgramFileObject == NULL ))
+ {
+ return(STATUS_INVALID_DEVICE_REQUEST);
+ }
+ pClientEle = (tCLIENTELE *)pRequest->Handle.AddressHandle;
+ CTEVerifyHandle(pClientEle,NBT_VERIFY_CLIENT,tCLIENTELE,&status);
+
+ {
+ PTRANSPORT_ADDRESS pRemoteAddress;
+ PTA_NETBIOS_ADDRESS pRemoteNetBiosAddress;
+ PTA_NETBIOS_EX_ADDRESS pRemoteNetbiosExAddress;
+ ULONG TdiAddressType;
+
+ pRemoteAddress = (PTRANSPORT_ADDRESS)pSendInfo->RemoteAddress;
+ TdiAddressType = pRemoteAddress->Address[0].AddressType;
+ pClientEle->AddressType = TdiAddressType;
+
+ if (TdiAddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) {
+ PTDI_ADDRESS_NETBIOS pNetbiosAddress;
+
+ pRemoteNetbiosExAddress = (PTA_NETBIOS_EX_ADDRESS)pRemoteAddress;
+
+ CTEMemCopy(pClientEle->EndpointName,
+ pRemoteNetbiosExAddress->Address[0].Address[0].EndpointName,
+ sizeof(pRemoteNetbiosExAddress->Address[0].Address[0].EndpointName));
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NetBt:Handling New Address Type with SessionName %16s\n",
+ pClientEle->EndpointName));
+
+ pNetbiosAddress = &pRemoteNetbiosExAddress->Address[0].Address[0].NetbiosAddress;
+ pName = pNetbiosAddress->NetbiosName;
+ NameType = pNetbiosAddress->NetbiosNameType;
+ NameLen = pRemoteNetbiosExAddress->Address[0].AddressLength -
+ FIELD_OFFSET(TDI_ADDRESS_NETBIOS_EX,NetbiosAddress) -
+ FIELD_OFFSET(TDI_ADDRESS_NETBIOS,NetbiosName);
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NetBt:NETBIOS address NameLen(%ld) Name %16s\n",NameLen,pName));
+ status = STATUS_SUCCESS;
+ } else if (TdiAddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ // don't need spin lock because the client can't close this address
+ // since they are in this call and the handle has a reference count > 0
+ //
+ //pClientEle->RefCount++;
+
+ // this routine gets a ptr to the netbios name out of the wierd
+ // TDI address syntax.
+ ASSERT(pSendInfo->RemoteAddressLength);
+ status = GetNetBiosNameFromTransportAddress(
+ pSendInfo->RemoteAddress,
+ &pName,
+ &NameLen,
+ &lNameType);
+ } else {
+ status = STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:Unable to get dest name from address in dgramsend"));
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ pSourceName = ((tADDRESSELE *)pClientEle->pAddress)->pNameAddr->Name;
+
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:Dgram Send to = %16.16s<%X>\n",pName,pName[15]));
+
+
+ {
+ ULONG RemoteIpAddress;
+
+ status = BuildSendDgramHdr(SendLength,
+ pDeviceContext,
+ pSourceName,
+ pName,
+ pBuffer,
+ &pDgramHdr,
+ &pTracker);
+
+
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+
+ //
+ // save the devicecontext that the client is sending on.
+ //
+ pTracker->pDeviceContext = (PVOID)pDeviceContext;
+ pTracker->Flags = DGRAM_SEND_FLAG;
+
+ //
+ // if the name is longer than 16 bytes, it's not a netbios name.
+ // skip wins, broadcast etc. and go straight to dns resolution
+ //
+
+ if (pClientEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) {
+ RemoteIpAddress = Nbt_inet_addr(pName);
+ } else {
+ RemoteIpAddress = 0;
+ }
+
+ if (RemoteIpAddress != 0) {
+ tNAMEADDR *pRemoteNameAddr;
+
+ //
+ // add this server name to the remote hashtable
+ //
+
+ pRemoteNameAddr = NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('8'));
+ if (pRemoteNameAddr != NULL)
+ {
+ tNAMEADDR *pTableAddress;
+
+ CTEZeroMemory(pRemoteNameAddr,sizeof(tNAMEADDR));
+ InitializeListHead(&pRemoteNameAddr->Linkage);
+ CTEMemCopy(pRemoteNameAddr->Name,pName,NETBIOS_NAME_SIZE);
+ pRemoteNameAddr->Verify = REMOTE_NAME;
+ pRemoteNameAddr->RefCount = 1;
+ pRemoteNameAddr->NameTypeState = STATE_RESOLVED | NAMETYPE_UNIQUE;
+ pRemoteNameAddr->AdapterMask = (CTEULONGLONG)-1;
+ pRemoteNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
+ pRemoteNameAddr->IpAddress = RemoteIpAddress;
+
+ status = AddToHashTable(
+ NbtConfig.pRemoteHashTbl,
+ pRemoteNameAddr->Name,
+ NbtConfig.pScope,
+ 0,
+ 0,
+ pRemoteNameAddr,
+ &pTableAddress);
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NbtConnectCommon ...AddRecordToHashTable %s Status %lx\n",pRemoteNameAddr->Name,status));
+ } else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (status == STATUS_SUCCESS) {
+ PUCHAR pCopyTo;
+
+ //
+ // Copy over the called name here.
+ //
+ pCopyTo = (PVOID)&pDgramHdr->SrcName.NameLength;
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("pCopyTo:%lx\n", pCopyTo));
+
+ pCopyTo += 1 + // Length field
+ 2 * NETBIOS_NAME_SIZE + // actual name in half-ascii
+ NbtConfig.ScopeLength; // length of scope
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("pCopyTo:%lx\n", pCopyTo));
+
+ ConvertToHalfAscii( pCopyTo,
+ pClientEle->EndpointName,
+ NbtConfig.pScope,
+ NbtConfig.ScopeLength);
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("Copied the remote name for dgram sends - IP\n"));
+
+ SendDgramContinue(pTracker,status);
+ status = STATUS_PENDING;
+ }
+ } else {
+// if ((pConnEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) ||
+// (NameLen > NETBIOS_NAME_SIZE)) {
+ if (NameLen > NETBIOS_NAME_SIZE) {
+ NBT_WORK_ITEM_CONTEXT *pContext;
+
+ pTracker->AddressType = pClientEle->AddressType;
+ if (pClientEle->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) {
+ //IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ //KdPrint(("$$$$$ Avoiding NETBIOS name translation on connection to %16s\n",pClientEle->RemoteName));
+ }
+ pContext = (NBT_WORK_ITEM_CONTEXT *)NbtAllocMem(sizeof(NBT_WORK_ITEM_CONTEXT),NBT_TAG('H'));
+ if (!pContext)
+ {
+ KdPrint(("Nbt: NbtConnect: couldn't alloc mem for pContext\n"));
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+ PUCHAR pCopyTo;
+
+ //
+ // Copy over the called name here.
+ //
+ pCopyTo = (PVOID)&pDgramHdr->SrcName.NameLength;
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("pCopyTo:%lx\n", pCopyTo));
+
+ pCopyTo += 1 + // Length field
+ 2 * NETBIOS_NAME_SIZE + // actual name in half-ascii
+ NbtConfig.ScopeLength; // length of scope
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("pCopyTo:%lx\n", pCopyTo));
+
+ ConvertToHalfAscii( pCopyTo,
+ pClientEle->EndpointName,
+ NbtConfig.pScope,
+ NbtConfig.ScopeLength);
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("Copied the remote name for dgram sends DNS\n"));
+
+ pContext->pTracker = NULL; // no query tracker
+ pContext->pClientContext = pTracker; // the client tracker
+ pContext->ClientCompletion = SendDgramContinue;
+ status = DoDnsResolve(pContext);
+ }
+ } else {
+ status = FindNameOrQuery(pTracker,
+ pName,
+ pDeviceContext,
+ SendDgramContinue,
+ NULL,
+ TRUE,
+ &pNameAddr);
+ }
+ }
+
+ // this routine checks the hash tables and does a name query if
+ // it can't find the name. If it finds the name, it returns
+ // STATUS_SUCCESS.
+
+ //
+ // in other words Pending was not returned...
+ //
+ if (status == STATUS_SUCCESS)
+ {
+ //
+ // don't set the status here since SendDgram cleans up the
+ // tracker and we don't want to clean it up again below
+ // if there is a failure.
+ //
+ SendDgram(pNameAddr,pTracker);
+
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // *** Error Handling Here ***
+ //
+#ifdef VXD
+ pTracker->pNameAddr = NULL;
+#endif
+
+ DgramSendCleanupTracker(pTracker,status,0);
+ }
+ else
+ if (status == STATUS_PENDING)
+ {
+ //
+ // do not return pending since the datagram is buffered and it
+ // is always completed.
+ //
+ status = STATUS_SUCCESS;
+ }
+
+
+ }
+
+ // the amount sent is the whole datagram, although we really don't
+ // know if it got sent since the name query phase has not ended yet
+ //
+ *pSentLength = SendLength;
+ //
+ // return the status to the client.
+ //
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+BuildSendDgramHdr(
+ IN ULONG SendLength,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PCHAR pSourceName,
+ IN PCHAR pName,
+ IN PVOID pBuffer,
+ OUT tDGRAMHDR **ppDgramHdr,
+ OUT tDGRAM_SEND_TRACKING **ppTracker
+ )
+/*++
+
+Routine Description
+
+ This routine builds a datagram header necessary for sending datagrams.
+ It include the to and from Netbios names and ip addresses.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+{
+ NTSTATUS status;
+ PCHAR pCopyTo;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tDGRAMHDR *pDgramHdr;
+ ULONG HdrLength;
+ ULONG HLength;
+ ULONG TotalLength;
+ PVOID pSendBuffer;
+ PVOID pNameBuffer;
+ PCTE_MDL pMdl;
+ CTELockHandle OldIrq;
+
+ CTEPagedCode();
+
+ HdrLength = DGRAM_HDR_SIZE + (NbtConfig.ScopeLength <<1);
+ HLength = ((HdrLength + 3 )/4)*4; // 4 byte aligned the hdr size
+ TotalLength = HLength + SendLength + NETBIOS_NAME_SIZE;
+
+ CTECountedAllocMem((PVOID *)&pDgramHdr,TotalLength);
+
+ if (!pDgramHdr)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ *ppDgramHdr = pDgramHdr;
+
+ // fill in the Dgram header
+ pDgramHdr->Flags = FIRST_DGRAM | (NbtConfig.PduNodeType >> 10);
+
+ pDgramHdr->DgramId = htons(GetTransactId());
+
+ pDgramHdr->SrcPort = htons(NBT_DATAGRAM_UDP_PORT);
+
+ //
+ // the length is the standard datagram length (dgram_hdr_size + 2* scope)
+ // minus size of the header that comes before the SourceName
+ //
+ pDgramHdr->DgramLength = htons( (USHORT)SendLength + (USHORT)DGRAM_HDR_SIZE
+ - (USHORT)(&((tDGRAMHDR *)0)->SrcName.NameLength)
+ + ( (USHORT)(NbtConfig.ScopeLength << 1) ));
+
+ CHECK_PTR(pDgramHdr);
+ pDgramHdr->PckOffset = 0; // not fragmented for now!
+ pDgramHdr->SrcIpAddr = htonl(pDeviceContext->IpAddress);
+
+ pCopyTo = (PVOID)&pDgramHdr->SrcName.NameLength;
+
+ pCopyTo = ConvertToHalfAscii(
+ pCopyTo,
+ pSourceName,
+ NbtConfig.pScope,
+ NbtConfig.ScopeLength);
+
+ //
+ // copy the destination name and scope to the pdu - we use this node's
+ //
+ ConvertToHalfAscii(pCopyTo,pName,NbtConfig.pScope,NbtConfig.ScopeLength);
+
+ //
+ // copy the name in to the buffer since we are completing the client's irp
+ // and we will lose his buffer with the dest name in it.
+ //
+ pNameBuffer = (PVOID)((PUCHAR)pDgramHdr + HLength);
+ CTEMemCopy(pNameBuffer,pName,NETBIOS_NAME_SIZE);
+
+ //
+ // copy the client's send buffer to our buffer so the send dgram can
+ // complete immediately.
+ //
+ pSendBuffer = (PVOID)((PUCHAR)pDgramHdr + HLength + NETBIOS_NAME_SIZE);
+ if (SendLength)
+ {
+#ifdef VXD
+ CTEMemCopy(pSendBuffer,pBuffer,SendLength);
+#else
+ {
+ ULONG BytesCopied;
+
+ status = TdiCopyMdlToBuffer(pBuffer,
+ 0,
+ pSendBuffer,
+ 0,
+ SendLength,
+ &BytesCopied);
+
+ if (NT_SUCCESS(status) && (BytesCopied == SendLength))
+ {
+ //
+ // Allocate an MDL since in NT the pBuffer is really an MDL
+ //
+ pMdl = IoAllocateMdl(
+ pSendBuffer,
+ SendLength,
+ FALSE,
+ FALSE,
+ NULL);
+ if (!pMdl)
+ {
+ CTECountedFreeMem((PVOID)pDgramHdr,TotalLength);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ else
+ {
+ //
+ // Lock the Mdl buffer down
+ //
+ MmBuildMdlForNonPagedPool(pMdl);
+ pSendBuffer = (PVOID)pMdl;
+ }
+
+ }
+ else
+ {
+ CTECountedFreeMem((PVOID)pDgramHdr,TotalLength);
+ return(STATUS_UNSUCCESSFUL);
+ }
+ }
+#endif
+ }
+ else
+ {
+ pSendBuffer = NULL;
+ }
+
+ //
+ // get a buffer for tracking Dgram Sends
+ //
+ pTracker = NbtAllocTracker();
+ if (pTracker)
+ {
+
+ CHECK_PTR(pTracker);
+ pTracker->SendBuffer.pBuffer = pSendBuffer;
+ pTracker->SendBuffer.Length = SendLength;
+ pTracker->SendBuffer.pDgramHdr = pDgramHdr;
+ pTracker->SendBuffer.HdrLength = HdrLength;
+ pTracker->pClientEle = NULL;
+ pTracker->pDestName = pNameBuffer;
+ pTracker->AllocatedLength = TotalLength;
+ pTracker->p1CNameAddr = NULL;
+
+ *ppTracker = pTracker;
+
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+#ifndef VXD
+ if (pSendBuffer)
+ {
+ IoFreeMdl(pMdl);
+ }
+#endif
+ CTECountedFreeMem((PVOID)pDgramHdr,TotalLength);
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ return(status);
+
+
+}
+//----------------------------------------------------------------------------
+ USHORT
+GetTransactId(
+ )
+/*++
+Routine Description:
+
+ This Routine increments the transaction id with the spin lock held.
+ It uses NbtConfig.JointLock.
+
+Arguments:
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+ USHORT TransactId;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ TransactId = GetTransactIdLocked();
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return (TransactId);
+
+}
+
+USHORT
+GetTransactIdLocked(
+)
+{
+ USHORT TransactId;
+ TransactId = NbtConfig.TransactionId++;
+
+#ifndef VXD
+ if (TransactId == 0xFFFF)
+ {
+ NbtConfig.TransactionId = WINS_MAXIMUM_TRANSACTION_ID +1;
+ }
+#else
+ if (TransactId == (DIRECT_DNS_NAME_QUERY_BASE - 1))
+ {
+ NbtConfig.TransactionId = 0;
+ }
+#endif
+ return (TransactId);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+CTECountedAllocMem(
+ PVOID *pBuffer,
+ ULONG Size
+ )
+/*++
+Routine Description:
+
+ This Routine allocates memory and counts the amount allocated so that it
+ will not allocate too much - generally this is used in datagram sends
+ where the send datagram is buffered.
+
+Arguments:
+
+ Size - the number of bytes to allocate
+ PVOID - a pointer to the memory or NULL if a failure
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (NbtMemoryAllocated > NbtConfig.MaxDgramBuffering)
+ {
+ *pBuffer = NULL;
+ }
+ else
+ {
+ NbtMemoryAllocated += Size;
+ *pBuffer = NbtAllocMem(Size,NBT_TAG('L'));
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+CTECountedFreeMem(
+ PVOID pBuffer,
+ ULONG Size
+ )
+/*++
+Routine Description:
+
+ This Routine frees memory and decrements the global count of acquired
+ memory.
+
+Arguments:
+
+ PVOID - a pointer to the memory to free
+ Size - the number of bytes to free
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ ASSERT(NbtMemoryAllocated >= Size);
+ if (NbtMemoryAllocated >= Size)
+ {
+ NbtMemoryAllocated -= Size;
+ }
+ else
+ {
+ NbtMemoryAllocated = 0;
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ CTEMemFree(pBuffer);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SendDgramContinue(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ )
+/*++
+
+Routine Description
+
+ This routine handles sending client data to the Transport TDI
+ interface after the destination name has resolved to an IP address.
+ This routine is given as the completion routine to the "QueryNameOnNet" call
+ in NbtSendDatagram, above. When a name query response comes in or the
+ timer times out after N retries.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ tNAMEADDR *pNameAddr=NULL;
+ ULONG lNameType;
+ PLIST_ENTRY pHead;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+ pHead = &pTracker->TrackerList;
+
+ DELETE_CLIENT_SECURITY(pTracker);
+
+ //
+ // attempt to find the destination name in the remote hash table. If its
+ // there, then send to it. For 1c names, this node may be the only node
+ // with the 1c name registered, so check the local table, since we skipped
+ // it if the name ended in 1c.
+ //
+ if ((status == STATUS_SUCCESS) ||
+ ( pTracker->pDestName[NETBIOS_NAME_SIZE-1] == 0x1c))
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pNameAddr = FindNameRemoteThenLocal(pTracker,&lNameType);
+
+ //
+ // check if it is a 1C name and if there is a name in the domain list
+ // If pNameAddr is not null, then the send to the domainlist will
+ // send to the p1CNameAddr after sending to pNameAddr
+ //
+ if ( pTracker->pDestName[NETBIOS_NAME_SIZE-1] == 0x1c
+
+ )
+ {
+ pTracker->p1CNameAddr = FindInDomainList(pTracker->pDestName,&DomainNames.DomainList);
+
+ //
+ // if there is no pNameAddr then just make the domain list
+ // name the only pNameAddr to send to.
+ //
+ if (!pNameAddr)
+ {
+ pNameAddr = pTracker->p1CNameAddr;
+ CHECK_PTR(pTracker);
+ pTracker->p1CNameAddr = NULL;
+ }
+
+ }
+
+ // check if the name resolved or we have a list of domain names
+ // derived from the lmhosts file and it is a 1C name send.
+ //
+ if (pNameAddr)
+ {
+ // increment this ref count so that it can't disappear
+ // during the send - decrement in the sendDgramCompletion
+ // routine
+ //
+ pNameAddr->RefCount++;
+
+ if (pTracker->p1CNameAddr)
+ {
+ pTracker->p1CNameAddr->RefCount++;
+ }
+
+ // overwrite the pDestName field with the pNameAddr value
+ // so that SendDgramContinue can send to Internet group names
+ //
+ pTracker->pNameAddr = pNameAddr;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // send the first datagram queued to this name
+ status = SendDgram(pNameAddr,pTracker);
+
+ // a failure ret code means the send failed, so cleanup
+ // the tracker etc. below.
+ if (NT_SUCCESS(status))
+ {
+ return;
+ }
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ }
+
+ //
+ // What can happen is TCP calls SessionStartupContinue with an error
+ // which then calls CTEIoComplete, however this request is still on
+ // the timer queue, so when the client request is serviced, this
+ // routine is called (TimerExpiry, MSnodeCompletion,
+ // CompleteClientReq, SendDgramContinue) which frees everything
+ // again! Presumably this is not isolated to Vxd-land.
+
+ // Note: the Timer is now stopped in QueryNameOnNet if it fails to
+ // send to TCP, which should remove this problem... still testing it
+ // so leave comment here for a while.
+ //
+
+
+ // this is the ERROR handling if something goes wrong with the send
+ // it cleans up the tracker and completes the client irp
+ //
+ // set this so that the cleanup routine does not try to dereference
+ // the nameAddr
+ CHECK_PTR(pTracker);
+
+ // check if pNameAddr refcount got incremented or not
+ if (!pNameAddr)
+ {
+ pTracker->pNameAddr = NULL;
+ }
+
+ if (status == STATUS_TIMEOUT)
+ {
+ status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ DgramSendCleanupTracker(pTracker,status,0);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+SendDgram(
+ IN tNAMEADDR *pNameAddr,
+ IN tDGRAM_SEND_TRACKING *pTracker
+ )
+/*++
+
+Routine Description
+
+ This routine handles sending client data to the Transport TDI
+ interface after the destination name has resolved to an IP address. The
+ routine specifically handles sending to internet group names where the destination
+ is a list of ip addresses.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+{
+ ULONG IpAddress;
+ NTSTATUS status;
+ PFILE_OBJECT pFileObject;
+
+ if (pNameAddr->NameTypeState & NAMETYPE_UNIQUE )
+ {
+ ((tDGRAMHDR *)pTracker->SendBuffer.pDgramHdr)->MsgType = DIRECT_UNIQUE;
+ }
+ else
+ if (pNameAddr->Name[0] == '*')
+ {
+ ((tDGRAMHDR *)pTracker->SendBuffer.pDgramHdr)->MsgType = BROADCAST_DGRAM;
+ }
+ else
+ {
+ // must be group, -
+ ((tDGRAMHDR *)pTracker->SendBuffer.pDgramHdr)->MsgType = DIRECT_GROUP;
+ }
+
+ //
+ // if it is an internet group name, then send to the list of addresses
+ //
+ if (pNameAddr->NameTypeState & NAMETYPE_INET_GROUP)
+ {
+
+ status = DatagramDistribution(pTracker,pNameAddr);
+
+ return(status);
+ }
+ else
+ {
+ //
+ // for sends to this node, use the ip address of the deviceContext
+ // if its a unique name.
+ //
+ if ((pNameAddr->Verify == REMOTE_NAME) ||
+ (!(pNameAddr->NameTypeState & NAMETYPE_UNIQUE)))
+ {
+ IpAddress = pNameAddr->IpAddress;
+
+ if (pNameAddr->NameTypeState & NAMETYPE_GROUP)
+ {
+ IpAddress = 0;
+ }
+ }
+ else
+ {
+ IpAddress = pTracker->pDeviceContext->IpAddress;
+ }
+
+ // flag that there are no more addresses in the list
+ CHECK_PTR(pTracker);
+ pTracker->IpListIndex = 0;
+
+ }
+
+ // send the Datagram...
+ if (pTracker->pDeviceContext->IpAddress)
+ {
+ pFileObject = pTracker->pDeviceContext->pDgramFileObject;
+ }
+ else
+ pFileObject = NULL;
+ status = UdpSendDatagram(
+ pTracker,
+ IpAddress,
+ pFileObject,
+ SendDgramCompletion,
+ pTracker, // context for completion
+ NBT_DATAGRAM_UDP_PORT,
+ NBT_DATAGRAM_SERVICE);
+
+ // the irp will be completed via SendDgramCompletion
+ // so don't complete it by the caller too
+ status = STATUS_PENDING;
+
+ return(status);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+SendDgramDist (
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the Executive Worker thread to send another
+ datagram for the 1C name datagram distribution function.
+
+Arguments:
+
+ Context -
+
+Return Value:
+
+ none
+
+--*/
+
+
+{
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ ULONG IpAddress;
+ PFILE_OBJECT pFileObject;
+
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
+
+ IpAddress = (ULONG)((NBT_WORK_ITEM_CONTEXT *)Context)->pClientContext;
+
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:DgramDistribution to name %15.15s<%X>:Ip %X, \n",
+ pTracker->pNameAddr->Name,pTracker->pNameAddr->Name[15],IpAddress));
+
+ // send the Datagram...
+ if (pTracker->pDeviceContext->IpAddress)
+ {
+ pFileObject = pTracker->pDeviceContext->pDgramFileObject;
+ }
+ else
+ pFileObject = NULL;
+ status = UdpSendDatagram(
+ pTracker,
+ IpAddress,
+ pFileObject,
+ SendDgramCompletion,
+ pTracker,
+ NBT_DATAGRAM_UDP_PORT,
+ NBT_DATAGRAM_SERVICE);
+
+ CTEMemFree(Context);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+SendDgramCompletion(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo)
+/*++
+Routine Description
+
+ This routine is hit when the
+ datagram has been sent by the transport and it completes the request back
+ to us ( may not have actually sent on the wire though ).
+
+ This routine also handles sending multiple datagrams for the InternetGroup name
+ case.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ ULONG IpAddress;
+ ULONG EndOfList;
+ CTELockHandle OldIrq;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ //
+ // The list ends in a -1 ipaddress, so stop when we see that
+ //
+ EndOfList = (ULONG)-1;
+
+ // if this an Internet group send, then there may be more addresses in
+ // the list to send to. So check the IpListIndex. For single
+ // sends, this value is set to 0 and the code will jump to the bottom
+ // where the client's irp will be completed.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ // decrement the ref count done during the send
+ pTracker->RCount--;
+
+ if (pTracker->IpListIndex)
+ {
+ if (pTracker->IpListIndex < LAST_DGRAM_DISTRIBUTION)
+ {
+ IpAddress = pTracker->pNameAddr->pIpList->IpAddr[
+ pTracker->IpListIndex++];
+
+ if (IpAddress != EndOfList)
+ {
+
+ pTracker->RCount++;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ CTEQueueForNonDispProcessing(pTracker,(PVOID)IpAddress,NULL,
+ SendDgramDist,pTracker->pDeviceContext);
+ return;
+
+ }
+ else
+ {
+ //
+ // set to this so that the next DgramDistTimeout will call
+ // DgramSendCleanupTracker
+ //
+ pTracker->IpListIndex = LAST_DGRAM_DISTRIBUTION;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return;
+ }
+ }
+ else
+ {
+ // we have just completed the last datagram distribution and we
+ // must let the DgramDistTimeout below free the tracker. If the
+ // timer has not been started, then fall through to call
+ // DgramSendCleanup in this routine.
+ //
+ if (pTracker->Connect.pTimer)
+ {
+ pTracker->IpListIndex = END_DGRAM_DISTRIBUTION;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return;
+ }
+ }
+ }
+ else
+ if ((pTracker->p1CNameAddr) &&
+ (pTracker->pNameAddr->Name[NETBIOS_NAME_SIZE-1] == 0x1c))
+ {
+ tNAMEADDR *pNameAddr;
+
+ //
+ // There may be a list of addresses obtained from lmhosts for a send
+ // to a 1c name. In this case do a datagram distribution.
+ //
+ //
+ // dereference the name that is in the remote cache since
+ // we are done sending to it and we are about to send to the
+ // 1CNameAddr from the DomainNames list.
+ //
+ NbtDereferenceName(pTracker->pNameAddr);
+
+ pNameAddr = pTracker->p1CNameAddr;
+ CHECK_PTR(pTracker);
+ pTracker->p1CNameAddr = NULL;
+
+ pTracker->pNameAddr = pNameAddr;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ DatagramDistribution(pTracker,pNameAddr);
+
+ return;
+
+ }
+
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ DgramSendCleanupTracker(pTracker,status,lInfo);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+DgramDistTimeout(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine handles a short timeout on a datagram distribution. It
+ checks if the dgram send is hung up in the transport doing an ARP and
+ then it does the next dgram send if the first is still hung up.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ tNAMEADDR *pNameAddr;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // After the last dgram has completed the iplistindex will be set
+ // to this and it is time to cleanup
+ //
+ if (pTracker->IpListIndex == END_DGRAM_DISTRIBUTION)
+ {
+ if (pTracker->RCount == 0)
+ {
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:Cleanup After DgramDistribution %15.15s<%X> \n",
+ pTracker->pNameAddr->Name,pTracker->pNameAddr->Name[15]));
+
+ //
+ // there may be another set of addresses to send to if there is
+ // an lmhost file
+ //
+ if (pTracker->p1CNameAddr)
+ {
+ ULONG IpAddress;
+
+ pNameAddr = pTracker->p1CNameAddr;
+ CHECK_PTR(pTracker);
+ pTracker->p1CNameAddr = NULL;
+
+ //
+ // Start up DgramDistribution for the new list
+ //
+ IpAddress = pNameAddr->pIpList->IpAddr[0];
+
+ //
+ // set this so that we can send the next datagram in
+ // SendDgramCompletion
+ //
+ pTracker->IpListIndex = 1;
+
+ //
+ // dereference the name that is in the remote cache since
+ // we are done sending to it and we are about to send to the
+ // 1CNameAddr from the DomainNames list.
+ //
+ NbtDereferenceName(pTracker->pNameAddr);
+
+ pTracker->pNameAddr = pNameAddr;
+ pTracker->RCount++;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ CTEQueueForNonDispProcessing(pTracker,(PVOID)IpAddress,NULL,
+ SendDgramDist,pTracker->pDeviceContext);
+
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ return;
+ }
+ else
+ {
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ DgramSendCleanupTracker(pTracker,STATUS_SUCCESS,0);
+ return;
+ }
+ }
+ else
+ {
+ //
+ // Wait for the dgram that has not completed yet - which may not
+ // be the last dgram , since ARP could hold one up much long
+ // than all the rest if the destination is dead. so start the timer
+ // again....
+ //
+ }
+ }
+ else
+ {
+ if (pTracker->IpListIndex == pTracker->SavedListIndex)
+ {
+ //
+ // The dgram send is hung up in the transport, so do the
+ // next one now
+ //
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:DgramDistribution hung up on ARP forcing next send\n"));
+
+ pTracker->SavedListIndex = pTracker->IpListIndex;
+
+ // increment to account for the decrement in SendDgram
+ pTracker->RCount++;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ SendDgramCompletion(pTracker,STATUS_SUCCESS,0);
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ return;
+
+ }
+ else
+ {
+
+ //
+ // Save the current index so we can check it the next time the timer
+ // expires
+ //
+ pTracker->SavedListIndex = pTracker->IpListIndex;
+ }
+
+ }
+
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+DatagramDistribution(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN tNAMEADDR *pNameAddr
+ )
+
+/*++
+Routine Description
+
+ This routine sends a single datagram for a 1C name. It then sends
+ the next one when this one completes. This is done so that if
+ multiple sends go to the gateway, one does not cancel the next
+ when an Arp is necessary to resolve the gateway.
+
+Arguments:
+
+ pTracker
+ pNameAddr
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+ NTSTATUS Locstatus;
+ tIPLIST *IpList;
+ ULONG Index;
+ ULONG IpAddress;
+ ULONG TotalNumber;
+ PFILE_OBJECT pFileObject;
+
+ // NOTE: this could be made to be paged code IF it was farmed out to
+ // a worker thread!!!
+ //
+ Index = 0;
+ IpList = pTracker->pNameAddr->pIpList;
+ //
+ // count the number of addresses to send to and put that in the tracker
+ // so we can count datagram completions
+ //
+ while (IpList->IpAddr[Index++] != (ULONG)-1);
+
+ TotalNumber = Index;
+ pTracker->IpListIndex = (USHORT)Index;
+ //
+ // When the proxy calls this routine the allocated length is set to
+ // zero. In that case we do not want to broadcast again since it
+ // could setup an infinite loop with another proxy on the same
+ // subnet.
+ //
+ if (pTracker->AllocatedLength == 0)
+ {
+ Index = 1;
+ }
+ else
+ {
+ Index = 0;
+ }
+
+ IpAddress = IpList->IpAddr[Index];
+
+ if (IpAddress != (ULONG)-1)
+ {
+
+ //
+ // set this so that we can send the next datagram in
+ // SendDgramCompletion
+ //
+ pTracker->IpListIndex = 1;
+
+ // for each send, increment ref count so it ends up a 0 when
+ // the last send completes
+ //
+ pTracker->RCount = 1;
+
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:DgramDistribution to name %15.15s<%X>:Ip %X, \n",
+ pNameAddr->Name,pNameAddr->Name[15],IpAddress));
+
+ // send the Datagram...
+ if (pTracker->pDeviceContext->IpAddress)
+ {
+ pFileObject = pTracker->pDeviceContext->pDgramFileObject;
+ }
+ else
+ pFileObject = NULL;
+ status = UdpSendDatagram(
+ pTracker,
+ IpAddress,
+ pFileObject,
+ SendDgramCompletion,
+ pTracker,
+ NBT_DATAGRAM_UDP_PORT,
+ NBT_DATAGRAM_SERVICE);
+
+ Locstatus = LockedStartTimer(
+ DGRAM_SEND_TIMEOUT,
+ pTracker,
+ DgramDistTimeout,
+ pTracker,
+ DgramDistTimeout,
+ 1,
+ pNameAddr,
+ FALSE);
+
+ if (!NT_SUCCESS(Locstatus))
+ {
+ CHECK_PTR(pTracker);
+ pTracker->Connect.pTimer = NULL;
+ }
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // we failed to send probably because of a lack of
+ // free memory
+ //
+ pTracker->RCount--;
+ DgramSendCleanupTracker(pTracker,STATUS_SUCCESS,0);
+
+ }
+ return(status);
+}
+//----------------------------------------------------------------------------
+ VOID
+DgramSendCleanupTracker(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN NTSTATUS status,
+ IN ULONG Length
+ )
+
+/*++
+Routine Description
+
+ This routine cleans up after a data gram send.
+
+Arguments:
+
+ pTracker
+ status
+ Length
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+ tNAMEADDR *pNameAddr=NULL;
+
+
+ //
+ // Undo the nameAddr increment done before the send started - if we have
+ // actually resolved the name - when the name does not resolve pNameAddr
+ // is set to NULL before calling this routine.
+ //
+ if (pTracker->pNameAddr)
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ NbtDereferenceName(pTracker->pNameAddr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+
+
+#ifndef VXD
+ // this check is necessary for the Proxy case, since it does not
+ // have a Buffer
+ //
+ if (pTracker->SendBuffer.pBuffer)
+ {
+ IoFreeMdl((PMDL)pTracker->SendBuffer.pBuffer);
+ }
+#endif
+ //
+ // free the buffer used for sending the data and free
+ // the tracker
+ //
+ CTECountedFreeMem((PVOID)pTracker->SendBuffer.pDgramHdr,
+ pTracker->AllocatedLength);
+
+ CTEFreeMem(pTracker);
+
+
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtSetEventHandler(
+ tCLIENTELE *pClientEle,
+ int EventType,
+ PVOID pEventHandler,
+ PVOID pEventContext
+ )
+/*++
+
+Routine Description
+
+ This routine sets the event handler specified to the clients event procedure
+ and saves the corresponding context value to return when that event is signaled.
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+
+
+ // first verify that the client element is valid
+ CTEVerifyHandle(pClientEle,NBT_VERIFY_CLIENT,tCLIENTELE,&status)
+
+ if (!pClientEle->pAddress)
+ {
+ return(STATUS_UNSUCCESSFUL);
+ }
+ CTESpinLock(pClientEle,OldIrq);
+
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:EventHandler # %X set, on name %16.16s<%X>\n",EventType,
+ ((tADDRESSELE *)pClientEle->pAddress)->pNameAddr->Name,
+ ((tADDRESSELE *)pClientEle->pAddress)->pNameAddr->Name[15]));
+
+ if (pEventHandler)
+ {
+ switch (EventType)
+ {
+ case TDI_EVENT_CONNECT:
+ pClientEle->evConnect = pEventHandler;
+ pClientEle->ConEvContext = pEventContext;
+ break;
+ case TDI_EVENT_DISCONNECT:
+ pClientEle->evDisconnect = pEventHandler;
+ pClientEle->DiscEvContext = pEventContext;
+ case TDI_EVENT_ERROR:
+ pClientEle->evError = pEventHandler;
+ pClientEle->ErrorEvContext = pEventContext;
+ break;
+ case TDI_EVENT_RECEIVE:
+ pClientEle->evReceive = pEventHandler;
+ pClientEle->RcvEvContext = pEventContext;
+ break;
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+ pClientEle->evRcvDgram = pEventHandler;
+ pClientEle->RcvDgramEvContext = pEventContext;
+ break;
+ case TDI_EVENT_RECEIVE_EXPEDITED:
+ pClientEle->evRcvExpedited = pEventHandler;
+ pClientEle->RcvExpedEvContext = pEventContext;
+ break;
+ case TDI_EVENT_SEND_POSSIBLE:
+ pClientEle->evSendPossible = pEventHandler;
+ pClientEle->SendPossEvContext = pEventContext;
+ break;
+
+ default:
+ ASSERTMSG("Invalid Event Type passed to SetEventHandler\n",
+ (PVOID)0L);
+
+
+ }
+ }
+ else
+ { //
+ // the event handlers are set to point to the TDI default event handlers
+ // and can only be changed to another one, but not to a null address,
+ // so if null is passed in, set to default handler.
+ //
+ switch (EventType)
+ {
+ case TDI_EVENT_CONNECT:
+#ifndef VXD
+ pClientEle->evConnect = TdiDefaultConnectHandler;
+#else
+ pClientEle->evConnect = NULL;
+#endif
+ pClientEle->ConEvContext = NULL;
+ break;
+ case TDI_EVENT_DISCONNECT:
+#ifndef VXD
+ pClientEle->evDisconnect = TdiDefaultDisconnectHandler;
+#else
+ pClientEle->evDisconnect = NULL;
+#endif
+ pClientEle->DiscEvContext = NULL;
+ case TDI_EVENT_ERROR:
+#ifndef VXD
+ pClientEle->evError = TdiDefaultErrorHandler;
+#else
+ pClientEle->evError = NULL;
+#endif
+ pClientEle->ErrorEvContext = NULL;
+ break;
+ case TDI_EVENT_RECEIVE:
+#ifndef VXD
+ pClientEle->evReceive = TdiDefaultReceiveHandler;
+#else
+ pClientEle->evReceive = NULL;
+#endif
+ pClientEle->RcvEvContext = NULL;
+ break;
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+#ifndef VXD
+ pClientEle->evRcvDgram = TdiDefaultRcvDatagramHandler;
+#else
+ pClientEle->evRcvDgram = NULL;
+#endif
+ pClientEle->RcvDgramEvContext = NULL;
+ break;
+ case TDI_EVENT_RECEIVE_EXPEDITED:
+#ifndef VXD
+ pClientEle->evRcvExpedited = TdiDefaultRcvExpeditedHandler;
+#else
+ pClientEle->evRcvExpedited = NULL;
+#endif
+ pClientEle->RcvExpedEvContext = NULL;
+ break;
+ case TDI_EVENT_SEND_POSSIBLE:
+#ifndef VXD
+ pClientEle->evSendPossible = TdiDefaultSendPossibleHandler;
+#else
+ pClientEle->evSendPossible = NULL;
+#endif
+ pClientEle->SendPossEvContext = NULL;
+ break;
+
+ default:
+ ASSERTMSG("Invalid Event Type passed to SetEventHandler\n",
+ (PVOID)0L);
+ }
+ }
+
+ CTESpinFree(pClientEle,OldIrq);
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtSendNodeStatus(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PCHAR pName,
+ IN PIRP pIrp,
+ IN PULONG pIpAddrsList,
+ IN PVOID ClientContext,
+ IN PVOID CompletionRoutine
+ )
+/*++
+
+Routine Description
+
+ This routine sends a node status message to another node.
+ It's called for two reasons:
+ 1) in response to nbtstat -a (or -A). In this case, CompletionRoutine that's
+ passed in is NodeStatusDone, and ClientContext is 0.
+ 2) in response to "net use \\foobar.microsoft.com" (or net use \\11.1.1.3)
+ In this case, CompletionRoutine that's passed in is SessionSetupContinue,
+ and ClientContext is the tracker that correspondes to session setup.
+
+ The ip addr(s) s of the destination can be passed in (pIpAddrsList) when we
+ want to send an adapter status to a particular host. (case 2 above and
+ nbtstat -A pass in the ip address(es) since they don't know the name)
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ ULONG lNameType;
+ ULONG Length;
+ PUCHAR pHdr;
+ tNAMEADDR *pNameAddr;
+ ULONG UNALIGNED * pAddress;
+ PFILE_OBJECT pFileObject;
+ ULONG IpAddress;
+ PCHAR pName0;
+
+
+
+ status = GetTracker(&pTracker);
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:Send Node Status to = %16.16s<%X>\n",pName,pName[15]));
+
+ pName0 = Nbt_inet_addr(pName) ? "*\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" : pName;
+
+ // the node status is almost identical with the query pdu so use it
+ // as a basis and adjust it .
+ //
+ pAddress = (ULONG UNALIGNED *)CreatePdu(pName0,
+ NbtConfig.pScope,
+ 0L,
+ 0,
+ eNAME_QUERY,
+ (PVOID)&pHdr,
+ &Length,
+ pTracker);
+ if (!pAddress)
+ {
+ FreeTracker(pTracker,RELINK_TRACKER);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // clear the recursion desired bit
+ //
+ ((PUSHORT)pHdr)[1] &= ~FL_RECURDESIRE;
+
+ // set the NBSTAT field to 21 rather than 20
+ pHdr[Length-3] = (UCHAR)QUEST_STATUS;
+
+ // fill in the tracker data block
+ // note that the passed in transport address must stay valid till this
+ // send completes
+ pTracker->SendBuffer.pDgramHdr = (PVOID)pHdr;
+ pTracker->SendBuffer.HdrLength = Length;
+ pTracker->SendBuffer.pBuffer = NULL;
+ CHECK_PTR(&pTracker);
+ pTracker->SendBuffer.Length = 0;
+ pTracker->Flags = REMOTE_ADAPTER_STAT_FLAG;
+
+ // one for the send completion and one for the node status completion
+ pTracker->RefCount = 2;
+
+ pTracker->pDestName = pName;
+ pTracker->pClientIrp = pIrp;
+ pTracker->pDeviceContext = (PVOID)pDeviceContext;
+
+ status = FindNameOrQuery(pTracker,
+ pName,
+ pDeviceContext,
+ SendNodeStatusContinue,
+ NULL,
+ FALSE,
+ &pNameAddr);
+
+ if (status == STATUS_SUCCESS)
+ {
+ //
+ // If the ip addr(s) is passed in then the name is '*', meaning, send
+ // an adapter status call to the ip address specified. See how many
+ // ip addrs are there, allocate that much memory and store them
+ //
+ if ((pIpAddrsList) && (*pIpAddrsList) && (pName[0] == '*'))
+ {
+ int i=0;
+
+ // caller is expected to make sure list terminates in 0 and is
+ // not bigger than MAX_IPADDRS_PER_HOST elements
+ while(pIpAddrsList[i])
+ i++;
+
+ ASSERT(i<MAX_IPADDRS_PER_HOST);
+ i++; // for the trailing 0
+ pNameAddr->pIpAddrsList = NbtAllocMem(i*sizeof(ULONG),NBT_TAG('M'));
+ if(!pNameAddr->pIpAddrsList)
+ {
+ FreeTracker(pTracker,RELINK_TRACKER);
+ CTEMemFree(pHdr);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ i = 0;
+ do
+ {
+ pNameAddr->pIpAddrsList[i] = pIpAddrsList[i];
+ } while(pIpAddrsList[i++]);
+ }
+
+ if (pName[0] == '*')
+ {
+ ASSERT(pNameAddr->pIpAddrsList);
+ }
+
+ //
+ // found the name in the remote hash table, so send to it after
+ // starting a timer to be sure we really do get a response
+ //
+
+ status = LockedStartTimer(
+ NbtConfig.uRetryTimeout,
+ pTracker,
+ NodeStatusCompletion,
+ ClientContext,
+ CompletionRoutine,
+ NbtConfig.uNumRetries,
+ pNameAddr,
+ FALSE);
+
+ if (NT_SUCCESS(status))
+ {
+ //
+ // if its a unique name on this node then use this devicecontext's
+ // ip address.
+ //
+ if ((pNameAddr->Verify == REMOTE_NAME) ||
+ (!(pNameAddr->NameTypeState & NAMETYPE_UNIQUE)))
+ {
+ //
+ // if we have multiple ipaddrs, just choose the first one
+ //
+ if(pNameAddr->pIpAddrsList)
+ {
+ IpAddress = pNameAddr->pIpAddrsList[0];
+ pNameAddr->IpAddress = IpAddress;
+ }
+ else
+ {
+ IpAddress = pNameAddr->IpAddress;
+ }
+
+ }
+ else
+ {
+ IpAddress = pTracker->pDeviceContext->IpAddress;
+ }
+
+ if (pDeviceContext->IpAddress)
+ {
+ pFileObject = pDeviceContext->pNameServerFileObject;
+ }
+ else
+ pFileObject = NULL;
+
+ // the tracker block is put on a global Q in the Config
+ // data structure to keep track of it.
+ //
+ ExInterlockedInsertTailList(&NbtConfig.NodeStatusHead,
+ &pTracker->Linkage,
+ &NbtConfig.SpinLock);
+
+ status = UdpSendDatagram(pTracker,
+ IpAddress,
+ pFileObject,
+ NameDgramSendCompleted,
+ pHdr, // context
+ NBT_NAMESERVICE_UDP_PORT,
+ NBT_NAME_SERVICE);
+
+ DereferenceTracker(pTracker);
+
+ //
+ // BUGBUG - Not returning status reflecting failure to send datagram
+ // to client. Client will eventually get STATUS_TIMEOUT.
+ //
+ return(STATUS_PENDING);
+ }
+ else
+ { //
+ // the timer failed to start so undo the ref done in FindNameOrQuery
+ //
+ LockedDereferenceName(pNameAddr);
+
+ FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
+ }
+
+
+ return(status);
+ }
+ else
+ if (NT_SUCCESS(status))
+ {
+ // i.e. pending was returned rather than success
+ return(status);
+ }
+ else
+ {
+ //
+ // Failed to FindNameOrQuery - probably out of memory
+ //
+ FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
+ return(status);
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtQueryFindName(
+ IN PTDI_CONNECTION_INFORMATION pInfo,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp,
+ IN BOOLEAN IsIoctl
+ )
+/*++
+
+Routine Description
+
+ This routine handles a Client's query to find a netbios name. It
+ ultimately returns the IP address of the destination.
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ PCHAR pName;
+ ULONG lNameType;
+ tNAMEADDR *pNameAddr;
+ PIRP pClientIrp;
+ ULONG NameLen;
+#ifndef VXD
+ PIO_STACK_LOCATION pIrpSp;
+ CTELockHandle OldIrq1;
+#endif
+
+ CTEPagedCode();
+
+ // this routine gets a ptr to the netbios name out of the wierd
+ // TDI address syntax.
+ if (!IsIoctl)
+ {
+ ASSERT(pInfo->RemoteAddressLength);
+ status = GetNetBiosNameFromTransportAddress(
+ pInfo->RemoteAddress,
+ &pName,
+ &NameLen,
+ &lNameType);
+
+ if (!NT_SUCCESS(status) || (lNameType != TDI_ADDRESS_NETBIOS_TYPE_UNIQUE)
+ || (NameLen > NETBIOS_NAME_SIZE))
+ {
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:Unable to get dest name from address in QueryFindName\n"));
+ return(STATUS_INVALID_PARAMETER);
+ }
+ }
+#ifndef VXD
+ else
+ {
+ pName = ((tIPADDR_BUFFER *)pInfo)->Name;
+ }
+#endif
+
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:QueryFindName for = %16.16s<%X>\n",pName,pName[15]));
+
+ //
+ // this will query the name on the network and call a routine to
+ // finish sending the datagram when the query completes.
+ //
+ status = GetTracker(&pTracker);
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+
+ pTracker->pClientIrp = pIrp;
+ pTracker->pDestName = pName;
+ pTracker->pDeviceContext = pDeviceContext;
+
+ //
+ // Set the FIND_NAME_FLAG here to indicate to the DNS name resolution code that
+ // this is not a session setup attempt so it can avoid the call to
+ // ConvertToHalfAscii (where pSessionHdr is NULL).
+ //
+ pTracker->Flags = REMOTE_ADAPTER_STAT_FLAG|FIND_NAME_FLAG;
+
+#ifndef VXD
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pIrpSp->Parameters.Others.Argument4 = (PVOID)pTracker;
+ status = NTCheckSetCancelRoutine( pIrp,FindNameCancel,pDeviceContext );
+
+ if (status == STATUS_CANCELLED )
+ {
+ FreeTracker(pTracker,RELINK_TRACKER);
+ return(status);
+ }
+#endif
+
+ status = FindNameOrQuery(pTracker,
+ pName,
+ pDeviceContext,
+ QueryNameCompletion,
+ NULL,
+ FALSE,
+ &pNameAddr);
+
+ if ((status == STATUS_SUCCESS) || (!NT_SUCCESS(status)))
+ {
+
+#ifndef VXD
+ IoAcquireCancelSpinLock(&OldIrq1);
+ pClientIrp = pTracker->pClientIrp;
+ if (pClientIrp == pIrp)
+ {
+ pTracker->pClientIrp = NULL;
+ }
+ pIrpSp->Parameters.Others.Argument4 = NULL;
+ IoReleaseCancelSpinLock(OldIrq1);
+#else
+ pClientIrp = pTracker->pClientIrp;
+#endif
+ FreeTracker(pTracker,RELINK_TRACKER);
+
+ if (pClientIrp)
+ {
+ ASSERT( pClientIrp == pIrp );
+
+ if (status == STATUS_SUCCESS)
+ {
+ status = CopyFindNameData(pNameAddr,pIrp,pDeviceContext->IpAddress);
+
+ LockedDereferenceName(pNameAddr);
+ }
+ }
+
+ //
+ // irp is already completed: return pending so we don't complete again
+ //
+ else
+ {
+ if (status == STATUS_SUCCESS)
+ {
+ LockedDereferenceName(pNameAddr);
+ }
+ status = STATUS_PENDING;
+ }
+ }
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+QueryNameCompletion(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ )
+/*++
+
+Routine Description
+
+ This routine handles a name query completion that was requested by the
+ client. If successful the client is returned the ip address of the name
+ passed in the original request.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq, OldIrq1;
+ tNAMEADDR *pNameAddr;
+ ULONG lNameType;
+ PIRP pClientIrp;
+#ifndef VXD
+ PIO_STACK_LOCATION pIrpSp;
+
+ //
+ // We now use Cancel SpinLocks to check the validity of our Irps
+ // This is to prevent a race condition in between the time that
+ // the Cancel routine (FindNameCancel) releases the Cancel SpinLock
+ // and acquires the joint lock and we complete the Irp over here
+ //
+ IoAcquireCancelSpinLock(&OldIrq1);
+#endif
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+ pClientIrp = pTracker->pClientIrp;
+ pTracker->pClientIrp = NULL;
+
+#ifndef VXD
+ IoReleaseCancelSpinLock(OldIrq1);
+
+//
+// Make sure all parameters are valid for the Irp processing
+//
+ if (! ((pClientIrp) &&
+ (pIrpSp = IoGetCurrentIrpStackLocation(pClientIrp)) &&
+ (pIrpSp->Parameters.Others.Argument4 == pTracker)))
+ {
+ KdPrint(("Nbt: irp from Tracker <0x%4X> has been cancelled already\n", pTracker));
+ FreeTracker( pTracker,RELINK_TRACKER );
+ return;
+ }
+#endif
+
+ pIrpSp->Parameters.Others.Argument4 = NULL;
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+#ifndef VXD
+ NTCancelCancelRoutine(pClientIrp);
+ NTClearFileObjectContext(pClientIrp);
+#endif
+
+ if (status == STATUS_SUCCESS)
+ {
+ //
+ // attempt to find the destination name in the local/remote hash table.
+ //
+ pNameAddr = FindNameRemoteThenLocal(pTracker,&lNameType);
+
+ if (pNameAddr)
+ {
+ status = CopyFindNameData(pNameAddr,pClientIrp,
+ pTracker->pDeviceContext->IpAddress);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ CTEIoComplete(pClientIrp,status,0xFFFFFFFF);
+
+ FreeTracker(pTracker,RELINK_TRACKER);
+ return;
+ }
+ }
+
+ // this is the ERROR handling if something goes wrong with the send
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ CTEIoComplete(pClientIrp,STATUS_IO_TIMEOUT,0L);
+
+ FreeTracker(pTracker,RELINK_TRACKER);
+
+}
+
+
+
+//----------------------------------------------------------------------------
+ VOID
+SendNodeStatusContinue(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ )
+/*++
+
+Routine Description
+
+ This routine handles sending a node status request to a node after the
+ name has been resolved on the net.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ tNAMEADDR *pNameAddr;
+ ULONG lNameType;
+ PLIST_ENTRY pHead;
+ tTIMERQENTRY *pTimerEntry;
+ ULONG IpAddress;
+ PCTE_IRP pIrp;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+ pHead = &pTracker->TrackerList;
+
+ DELETE_CLIENT_SECURITY(pTracker);
+
+ //
+ // attempt to find the destination name in the remote hash table. If its
+ // there, then send to it.
+ //
+ if (status == STATUS_SUCCESS)
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pNameAddr = FindNameRemoteThenLocal(pTracker,&lNameType);
+
+ if (pNameAddr)
+ {
+ // increment refcount so the name does not disappear out from under us
+ // dereference when we get the response or timeout
+ pNameAddr->RefCount++;
+ //
+ // found the name in the remote hash table, so send to it after
+ // starting a timer to be sure we really do get a response
+ //
+ status = StartTimer(
+ NbtConfig.uRetryTimeout,
+ (PVOID)pTracker, // context value
+ NULL, // context2 value
+ NodeStatusCompletion,
+ NULL,
+ NodeStatusDone,
+ NbtConfig.uNumRetries,
+ &pTimerEntry);
+
+ if (NT_SUCCESS(status))
+ {
+ PFILE_OBJECT pFileObject;
+
+ pTracker->Connect.pNameAddr = pNameAddr;
+ pTracker->Connect.pTimer = pTimerEntry;
+
+ //
+ // if the name is on this node then use this devicecontext
+ // ip address (if a unique name)
+ //
+ if ((pNameAddr->Verify == REMOTE_NAME) ||
+ (!(pNameAddr->NameTypeState & NAMETYPE_UNIQUE)))
+ {
+ IpAddress = pNameAddr->IpAddress;
+ }
+ else
+ {
+ IpAddress = pTracker->pDeviceContext->IpAddress;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // send the Datagram...
+ if (pTracker->pDeviceContext->IpAddress)
+ {
+ pFileObject = pTracker->pDeviceContext->pNameServerFileObject;
+ }
+ else
+ pFileObject = NULL;
+
+ // the tracker block is put on a global Q in the Config
+ // data structure to keep track of it.
+ //
+ ExInterlockedInsertTailList(&NbtConfig.NodeStatusHead,
+ &pTracker->Linkage,
+ &NbtConfig.SpinLock);
+
+ status = UdpSendDatagram(pTracker,
+ IpAddress,
+ pFileObject,
+ NameDgramSendCompleted,
+ pTracker->SendBuffer.pDgramHdr, // context
+ NBT_NAMESERVICE_UDP_PORT,
+ NBT_NAME_SERVICE);
+
+ //
+ // this undoes one of two ref's added in NbtSendNodeStatus
+ //
+ DereferenceTracker(pTracker);
+ // if the send fails, the timer will resend it...so no need
+ // to check the return code here.
+ return;
+ }
+ else
+ {
+ NbtDereferenceName(pNameAddr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ // this is the ERROR handling if something goes wrong with the send
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ pIrp = pTracker->pClientIrp;
+ pTracker->pClientIrp = NULL;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
+
+ CTEIoComplete(pIrp,STATUS_IO_TIMEOUT,0L);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NodeStatusDone(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ )
+/*++
+
+Routine Description
+
+ This routine handles sending nodes status data back up to the client when
+ the node status request completes on the network. This routine is the
+ client completion routine of the timer started above.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ PCTE_IRP pIrp;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ LOCATION(0x3E);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ pIrp = pTracker->pClientIrp;
+ pTracker->pClientIrp = NULL;
+
+ // remove the reference done in FindNameOrQuery
+ //
+ NbtDereferenceName(pTracker->Connect.pNameAddr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // the tracker block was unlinked in DecodeNodeStatusResponse,
+ // and its header was freed when the send completed, so just relink
+ // it here - this deref should do the relink.
+ //
+ DereferenceTracker(pTracker);
+
+ if (status == STATUS_SUCCESS ||
+ status == STATUS_BUFFER_OVERFLOW ) // Only partial data copied
+ {
+ // -1 means the receive length is already set in the irp
+ CTEIoComplete(pIrp,status,0xFFFFFFFF);
+ }
+ else
+ {
+ //
+ // failed to get the adapter status, so
+ // return failure status to the client.
+ //
+
+ CTEIoComplete(pIrp,STATUS_IO_TIMEOUT,0);
+ }
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+CopyFindNameData(
+ IN tNAMEADDR *pNameAddr,
+ IN PIRP pIrp,
+ IN ULONG SrcAddress)
+
+/*++
+Routine Description:
+
+ This Routine copies data received from the net node status response to
+ the client's irp.
+
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ PFIND_NAME_HEADER pFindNameHdr;
+ PFIND_NAME_BUFFER pFindNameBuffer;
+ PULONG pIpAddr;
+ ULONG BuffSize;
+ ULONG DataLength;
+ ULONG NumNames;
+ ULONG i;
+
+ if (pNameAddr->NameTypeState & NAMETYPE_INET_GROUP)
+ {
+ NumNames = 0;
+ pIpAddr = pNameAddr->pIpList->IpAddr;
+ while (*pIpAddr != (ULONG)-1)
+ {
+ pIpAddr++;
+ NumNames++;
+ }
+ }
+ else
+ {
+ NumNames = 1;
+ }
+
+#ifdef VXD
+ DataLength = ((NCB*)pIrp)->ncb_length ;
+#else
+ DataLength = MmGetMdlByteCount( pIrp->MdlAddress ) ;
+#endif
+
+ BuffSize = sizeof(FIND_NAME_HEADER) + NumNames*sizeof(FIND_NAME_BUFFER);
+
+ //
+ // Make sure we don't overflow our buffer
+ //
+ if ( BuffSize > DataLength )
+ {
+ if ( DataLength <= sizeof( FIND_NAME_HEADER ))
+ NumNames = 0 ;
+ else
+ NumNames = (DataLength - sizeof(FIND_NAME_HEADER)) /
+ sizeof(FIND_NAME_BUFFER) ;
+
+ BuffSize = sizeof(FIND_NAME_HEADER) + NumNames*sizeof(FIND_NAME_BUFFER);
+ }
+
+ // sanity check that we are not allocating more than 64K for this stuff
+ if (BuffSize > 0xFFFF)
+ {
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ pFindNameHdr = NbtAllocMem((USHORT)BuffSize,NBT_TAG('N'));
+ if (!pFindNameHdr)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // Fill out the find name structure with zeros first
+ CTEZeroMemory((PVOID)pFindNameHdr,BuffSize);
+
+ pFindNameBuffer = (PFIND_NAME_BUFFER)((PUCHAR)pFindNameHdr + sizeof(FIND_NAME_HEADER));
+
+ pFindNameHdr->node_count = (USHORT)NumNames;
+ pFindNameHdr->unique_group = (pNameAddr->NameTypeState & NAMETYPE_UNIQUE) ?
+ UNIQUE_NAME : GROUP_NAME;
+
+ SrcAddress = htonl(SrcAddress);
+ if (pNameAddr->NameTypeState & NAMETYPE_INET_GROUP)
+ {
+ pIpAddr = pNameAddr->pIpList->IpAddr;
+ for (i=0;i < NumNames ;i++)
+ {
+ // Note: the source and destination address appear to be
+ // reversed since they are supposed to be the source and
+ // destination of the response to the findname query, hence
+ // the destination of the response is this node and the
+ // source is the other node.
+ *(ULONG UNALIGNED *)&pFindNameBuffer->source_addr[2] = htonl(*pIpAddr);
+ pIpAddr++;
+ *(ULONG UNALIGNED *)&pFindNameBuffer->destination_addr[2] = SrcAddress;
+ pFindNameBuffer++;
+
+ }
+ }
+ else
+ {
+ //
+ // if the name is on this node then use the address of this device
+ // context - if its a unique name.
+ //
+ if ((pNameAddr->Verify == REMOTE_NAME) ||
+ (!(pNameAddr->NameTypeState & NAMETYPE_UNIQUE)))
+ {
+ *(ULONG UNALIGNED *)&pFindNameBuffer->source_addr[2] = htonl(pNameAddr->IpAddress);
+ }
+ else
+ {
+
+ *(ULONG UNALIGNED *)&pFindNameBuffer->source_addr[2] = SrcAddress;
+
+ }
+ *(ULONG UNALIGNED *)&pFindNameBuffer->destination_addr[2] = SrcAddress;
+ }
+
+#ifdef VXD
+ CTEMemCopy( ((NCB*)pIrp)->ncb_buffer,
+ pFindNameHdr,
+ BuffSize ) ;
+ ASSERT( ((NCB*)pIrp)->ncb_length >= BuffSize ) ;
+ ((NCB*)pIrp)->ncb_length = BuffSize ;
+ status = STATUS_SUCCESS ;
+#else
+ //
+ // copy the buffer to the client's MDL
+ //
+ status = TdiCopyBufferToMdl (
+ pFindNameHdr,
+ 0,
+ BuffSize,
+ pIrp->MdlAddress,
+ 0,
+ &DataLength);
+
+ pIrp->IoStatus.Information = DataLength;
+ pIrp->IoStatus.Status = status;
+#endif
+
+ CTEMemFree((PVOID)pFindNameHdr);
+
+ return(status);
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+FreeTracker(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN ULONG Actions
+ )
+/*++
+
+Routine Description:
+
+ This routine cleans up a Tracker block and puts it back on the free
+ queue.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(&NbtConfig,OldIrq);
+
+ if (Actions & REMOVE_LIST)
+ {
+ //
+ // unlink the tracker block from the NodeStatus Q
+ RemoveEntryList(&pTracker->Linkage);
+ }
+
+ if (Actions & FREE_HDR)
+ {
+ // return the datagram hdr to the free pool
+ //
+ if (pTracker->SendBuffer.pDgramHdr)
+ {
+ CTEMemFree((PVOID)pTracker->SendBuffer.pDgramHdr);
+ }
+
+ }
+ //
+ CHECK_PTR(pTracker);
+
+#if DBG
+ {
+ PLIST_ENTRY pHead,pEntry;
+ tDGRAM_SEND_TRACKING *pTrack;
+
+ //
+ // check if the tracker is already in the list or not!
+ //
+ pHead = &NbtConfig.DgramTrackerFreeQ;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pTrack = CONTAINING_RECORD(pEntry,tDGRAM_SEND_TRACKING,Linkage);
+ ASSERT(pTrack != pTracker);
+ pEntry = pEntry->Flink;
+ }
+
+ ASSERT(pTracker->Verify == NBT_VERIFY_TRACKER);
+
+ pTracker->Verify -= 10;
+ pTracker->pClientIrp = (PVOID)0x1F1F1F1F;
+
+ pTracker->pConnEle = (PVOID)0x1F1F1F1F;
+ pTracker->SendBuffer.HdrLength = 0x1F1F1F1F;
+ pTracker->SendBuffer.pDgramHdr = (PVOID)0x1F1F1F1F;
+ pTracker->SendBuffer.Length = 0x1F1F1F1F;
+ pTracker->SendBuffer.pBuffer = (PVOID)0x1F1F1F1F;
+ pTracker->pDeviceContext = (PVOID)0x1F1F1F1F;
+ pTracker->pTimer = (PVOID)0x1F1F1F1F;
+ pTracker->RefCount = 0x1F1F1F1F;
+ pTracker->pDestName = (PVOID)0x1F1F1F1F;
+ pTracker->pNameAddr = (PVOID)0x1F1F1F1F;
+#ifdef VXD
+ pTracker->pchDomainName = (PVOID)0x1F1F1F1F;
+#endif
+ pTracker->pTimeout = (PVOID)0x1F1F1F1F;
+ pTracker->SrcIpAddress = 0x1F1F1F1F;
+ pTracker->CompletionRoutine = (PVOID)0x1F1F1F1F;
+ pTracker->Flags = 0x1F1F;
+ }
+#endif
+
+ CHECK_PTR(pTracker);
+ pTracker->SendBuffer.pDgramHdr = NULL;
+ if (pTracker->IpList) {
+ ASSERT(pTracker->NumAddrs != 0);
+ CTEMemFree(pTracker->IpList);
+
+ pTracker->IpList = NULL;
+ pTracker->NumAddrs = 0x1F1F1F1F;
+ }
+ CTESpinFree(&NbtConfig,OldIrq);
+
+ //REMOVE_FROM_LIST(&pTracker->DebugLinkage);
+ ExInterlockedInsertTailList(&NbtConfig.DgramTrackerFreeQ,
+ &pTracker->Linkage,
+ &NbtConfig.SpinLock);
+
+
+
+}
+//----------------------------------------------------------------------------
+ VOID
+DereferenceIfNotInRcvHandler
+(
+ IN tCONNECTELE *pConnEle,
+ IN tLOWERCONNECTION *pLowerConn
+ )
+/*++
+
+Routine Description
+
+ This routine used to coordinate with the recv handler and not do the
+ dereference if it was in the rcv handler. Now it does it anyway and
+ the recv handler checks if pUpperConnection is still valid anywhere it
+ releases the spin lock and gets it again.
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+
+ PUSH_LOCATION(0x66);
+ NbtDereferenceConnection(pConnEle);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtQueryAdapterStatus(
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT PVOID *ppAdapterStatus,
+ IN OUT PLONG pSize
+ )
+/*++
+
+Routine Description
+
+ This routine creates a list of netbios names that are registered and
+ returns a pointer to the list in pAdapterStatus.
+
+ This routine can be called with a Null DeviceContext meaning, get the
+ remote hash table names, rather than the local hash table names.
+
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ NTSTATUS status;
+ CTELockHandle OldIrq1;
+ LONG Count=0;
+ LONG i,j;
+ LONG BuffSize;
+ PADAPTER_STATUS pAdapterStatus;
+ PLIST_ENTRY pEntry;
+ PLIST_ENTRY pHead;
+ PNAME_BUFFER pNameBuffer;
+ tADDRESSELE *pAddressEle;
+ BOOL fOverFlow = FALSE ;
+ tNAMEADDR *pNameAddr;
+ tHASHTABLE *pHashTable;
+ ULONG NameSize;
+ USHORT MaxAllowed;
+ PUCHAR pMacAddr;
+
+ // a null value for devicecontext means get the remote hash table entries
+ // - do this check without holding the spin lock because the macro does
+ // a return if it fails - which of course would not release the spin lock.
+ if (pDeviceContext)
+ {
+ // validate the device context
+ CTEVerifyHandle(pDeviceContext,NBT_VERIFY_DEVCONTEXT,tDEVICECONTEXT,&status)
+ }
+
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ if (pDeviceContext)
+ {
+
+ // count the number of netbios names
+ //
+ // CountLocalNames returns all names except the '*' names and resolving names.
+ // Now, we come here and bump up the count by one (on assumption that the only
+ // '*' name is the "*0000000" name). However, there are now al least two other
+ // names - "*SMBSERVER and the bowser name.
+ //
+ // So, count here only.
+ //
+ Count = 0;
+ for (i=0;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ )
+ {
+ pHead = &NbtConfig.pLocalHashTbl->Bucket[i];
+ pEntry = pHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ //
+ // don't want unresolved names, or the broadcast name
+ //
+ if (!(pNameAddr->NameTypeState & STATE_RESOLVING))
+ // && (pNameAddr->Name[0] != '*')) count these!!
+ {
+ Count++;
+ }
+ }
+ }
+
+ // get the list of addresses for this device - local hash table
+ pHead = &NbtConfig.AddressHead;
+ pEntry = pHead->Flink;
+ NameSize = sizeof(NAME_BUFFER);
+ }
+ else
+ {
+ // get the list of addresses for this device - remote hash table
+ Count = 0;
+ pHashTable = NbtConfig.pRemoteHashTbl;
+ for (i=0;i < pHashTable->lNumBuckets ;i++ )
+ {
+ pHead = &pHashTable->Bucket[i];
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pEntry = pEntry->Flink;
+ Count++;
+ }
+ }
+ pHead = &pHashTable->Bucket[0];
+ pEntry = pHead->Flink;
+ NameSize = sizeof(tREMOTE_CACHE);
+
+ }
+
+ // Allocate Memory for the adapter status
+ BuffSize = sizeof(ADAPTER_STATUS) + Count*NameSize;
+
+ //
+ // Is our status buffer size greater then the user's buffer?
+ //
+ if ( BuffSize > *pSize )
+ {
+ fOverFlow = TRUE;
+
+ //
+ // Recalc how many names will fit
+ //
+ if ( *pSize <= sizeof(ADAPTER_STATUS) )
+ Count = 0 ;
+ else
+ Count = ( *pSize - sizeof(ADAPTER_STATUS)) / NameSize ;
+
+ BuffSize = sizeof(ADAPTER_STATUS) + Count*NameSize;
+ }
+
+ pAdapterStatus = NbtAllocMem((USHORT)BuffSize,NBT_TAG('O'));
+ if (!pAdapterStatus)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // Fill out the adapter status structure with zeros first
+ CTEZeroMemory((PVOID)pAdapterStatus,BuffSize);
+
+ //
+ // Fill in the MAC address
+ //
+ if (pDeviceContext)
+ {
+ pMacAddr = &pDeviceContext->MacAddress.Address[0];
+ }
+ else
+ {
+ tDEVICECONTEXT *pDevContext;
+
+ // use the first adapter on the list to get the Ip address
+ pDevContext = CONTAINING_RECORD(NbtConfig.DeviceContexts.Flink,tDEVICECONTEXT,Linkage);
+ pMacAddr = &pDevContext->MacAddress.Address[0];
+ }
+
+ CTEMemCopy(&pAdapterStatus->adapter_address[0],
+ pMacAddr,
+ sizeof(tMAC_ADDRESS));
+
+ pAdapterStatus->rev_major = 0x03;
+ pAdapterStatus->adapter_type = 0xFE; // pretend it is an ethernet adapter
+
+ //
+ // in the VXD land limit the number of Ncbs to 64
+ //
+#ifndef VXD
+ MaxAllowed = 0xFFFF;
+ pAdapterStatus->max_cfg_sess = (USHORT)MaxAllowed;
+ pAdapterStatus->max_sess = (USHORT)MaxAllowed;
+#else
+ MaxAllowed = 64;
+ pAdapterStatus->max_cfg_sess = pDeviceContext->cMaxSessions;
+ pAdapterStatus->max_sess = pDeviceContext->cMaxSessions;
+#endif
+
+ pAdapterStatus->free_ncbs = (USHORT)MaxAllowed;
+ pAdapterStatus->max_cfg_ncbs = (USHORT)MaxAllowed;
+ pAdapterStatus->max_ncbs = (USHORT)MaxAllowed;
+
+ pAdapterStatus->max_dgram_size = MAX_NBT_DGRAM_SIZE;
+ pAdapterStatus->max_sess_pkt_size = 0xffff;
+
+ // get the address of the name buffer at the end of the adapter status
+ // structure so we can copy the names into this area.
+ pNameBuffer = (PNAME_BUFFER)((ULONG)pAdapterStatus + sizeof(ADAPTER_STATUS));
+
+ i = 0;
+ j = 0;
+ while (Count)
+ {
+ if (pDeviceContext)
+ {
+ // ***** LOCAL HASH TABLE QUERY *****
+
+ // get out of while if we reach the end of the list
+ if (pEntry == pHead)
+ {
+ break;
+ }
+
+ pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
+ pNameAddr = pAddressEle->pNameAddr;
+
+ pEntry = pEntry->Flink;
+ //
+ // skip the broadcast name and any permanent names that are
+ // registered as quick names(i.e. not registered on the net).
+ //
+ if ((pAddressEle->pNameAddr->Name[0] == '*') ||
+ (pAddressEle->pNameAddr->NameTypeState & NAMETYPE_QUICK))
+ {
+ Count--;
+ continue;
+ }
+
+ }
+
+ else
+ {
+ BOOLEAN done=FALSE;
+ ULONG Ttl;
+ BOOLEAN NewChain=FALSE;
+
+ // ***** REMOTE HASH TABLE QUERY *****
+
+ // for the remote table, skip over scope records.
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ while (TRUE)
+ {
+ if (j == pHashTable->lNumBuckets)
+ {
+ // no more hash buckets so get out
+ done = TRUE;
+ break;
+ }
+
+ if ((pEntry != pHead))
+ {
+ // don't go to the next entry of a new chain since we
+ // set pEntry in the else below on the previous loop
+ // through the while
+ if (!NewChain)
+ {
+ pEntry = pEntry->Flink;
+ }
+ break;
+ }
+ else
+ {
+ // reached the end of this hash chain so go to the next
+ // chain.
+ pHead = &pHashTable->Bucket[++j];
+ pEntry = pHead->Flink;
+ NewChain = TRUE;
+ }
+ }
+
+ // get out of the while loop if at end of hash table
+ if (done)
+ break;
+ if (NewChain)
+ {
+ // this will set pNameAddr, by looping around again
+ continue;
+ }
+
+
+ // don't return scope records or resolving records
+ //
+ if ((pNameAddr->NameTypeState & NAMETYPE_SCOPE) ||
+ (!(pNameAddr->NameTypeState & STATE_RESOLVED)))
+ {
+ // decrement the number of names returned.
+ pAdapterStatus->name_count--;
+ Count--;
+ continue;
+ }
+ //
+ // the remote cache query has a different structure that includes
+ // the ip address. Return the ip address to the caller.
+ //
+ if (pNameAddr->NameTypeState & NAMETYPE_INET_GROUP)
+ {
+ // if is is an internet group name, return just the first
+ // ip address in the group.
+ ((tREMOTE_CACHE *)pNameBuffer)->IpAddress = pNameAddr->pIpList->IpAddr[0];
+ }
+ else
+ ((tREMOTE_CACHE *)pNameBuffer)->IpAddress = pNameAddr->IpAddress;
+
+ // preloaded entries do not timeout
+ //
+ if (pNameAddr->NameTypeState & PRELOADED)
+ {
+ Ttl = 0xFFFFFFFF;
+ }
+ else
+ {
+ Ttl = ((pNameAddr->TimeOutCount+1) * REMOTE_HASH_TIMEOUT)/1000;
+ }
+
+ ((tREMOTE_CACHE *)pNameBuffer)->Ttl = Ttl;
+ }
+
+ pNameBuffer->name_flags = (pNameAddr->NameTypeState & NAMETYPE_UNIQUE) ?
+ UNIQUE_NAME : GROUP_NAME;
+
+ switch (pNameAddr->NameTypeState & NAME_STATE_MASK)
+ {
+ default:
+ case STATE_RESOLVED:
+ pNameBuffer->name_flags |= REGISTERED;
+ break;
+
+ case STATE_CONFLICT:
+ pNameBuffer->name_flags |= DUPLICATE;
+ break;
+
+ case STATE_RELEASED:
+ pNameBuffer->name_flags |= DEREGISTERED;
+ break;
+
+ case STATE_RESOLVING:
+ pNameBuffer->name_flags |= REGISTERING;
+ break;
+
+ }
+
+ //
+ // name number 0 corresponds to perm.name name, so start from 1
+ //
+ pNameBuffer->name_num = i+1;
+
+ CTEMemCopy(pNameBuffer->name,pNameAddr->Name,NETBIOS_NAME_SIZE);
+
+ if (pDeviceContext)
+ {
+ pNameBuffer++;
+ }
+ else
+ ((tREMOTE_CACHE *)pNameBuffer)++;
+
+ Count--;
+ i++;
+
+ }
+
+ pAdapterStatus->name_count = (USHORT)i;
+
+ //
+ // return the ptr to this wonderful structure of goodies
+ //
+ *ppAdapterStatus = (PVOID)pAdapterStatus;
+ *pSize = BuffSize;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ return fOverFlow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS ;
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtQueryConnectionList(
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT PVOID *ppConnList,
+ IN OUT PLONG pSize
+ )
+/*++
+
+Routine Description
+
+ This routine creates a list of netbios connections and returns them to the
+ client. It is used by the "NbtStat" console application.
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ CTELockHandle OldIrq1;
+ CTELockHandle OldIrq2;
+ CTELockHandle OldIrq3;
+ LONG Count;
+ LONG i;
+ LONG BuffSize;
+ PLIST_ENTRY pEntry;
+ PLIST_ENTRY pEntry1;
+ PLIST_ENTRY pEntry2;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pHead1;
+ PLIST_ENTRY pHead2;
+ BOOL fOverFlow = FALSE ;
+ ULONG NameSize;
+ tCONNECTIONS *pCons;
+ tCONNECTION_LIST *pConnList;
+ tADDRESSELE *pAddressEle;
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnEle;
+ tCLIENTELE *pClient;
+
+ // locking the joint lock is enough to prevent new addresses from being
+ // added to the list while we count the list.
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ // go through the list of addresses, then the list of clients on each
+ // address and then the list of connection that are in use and those that
+ // are currently Listening.
+ //
+ Count = 0;
+ pHead = &NbtConfig.AddressHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
+
+ CTESpinLock(pAddressEle,OldIrq2);
+ pHead1 = &pAddressEle->ClientHead;
+ pEntry1 = pHead1->Flink;
+ while (pEntry1 != pHead1)
+ {
+ pClient = CONTAINING_RECORD(pEntry1,tCLIENTELE,Linkage);
+ pEntry1 = pEntry1->Flink;
+
+ CTESpinLock(pClient,OldIrq3);
+ pHead2 = &pClient->ConnectActive;
+ pEntry2 = pHead2->Flink;
+ while (pEntry2 != pHead2)
+ {
+ // count the connections in use
+ pEntry2 = pEntry2->Flink;
+ Count++;
+ }
+ pHead2 = &pClient->ListenHead;
+ pEntry2 = pHead2->Flink;
+ while (pEntry2 != pHead2)
+ {
+ // count the connections listening
+ pEntry2 = pEntry2->Flink;
+ Count++;
+ }
+ CTESpinFree(pClient,OldIrq3);
+ }
+ CTESpinFree(pAddressEle,OldIrq2);
+ pEntry = pEntry->Flink;
+ }
+ NameSize = sizeof(tCONNECTIONS);
+
+ // Allocate Memory for the adapter status
+ BuffSize = sizeof(tCONNECTION_LIST) + Count*NameSize;
+
+ //
+ // Is our status buffer size greater then the user's buffer?
+ //
+ if ( BuffSize > *pSize )
+ {
+ fOverFlow = TRUE;
+
+ //
+ // Recalc how many names will fit
+ //
+ if ( *pSize <= sizeof(tCONNECTION_LIST) )
+ Count = 0 ;
+ else
+ Count = ( *pSize - sizeof(tCONNECTION_LIST)) / NameSize ;
+
+ BuffSize = sizeof(tCONNECTION_LIST) + Count*NameSize;
+ }
+
+ pConnList = NbtAllocMem(BuffSize,NBT_TAG('P'));
+ if (!pConnList)
+ {
+ CTESpinFree(&NbtConfig,OldIrq1);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // Fill out the adapter status structure with zeros first
+ CTEZeroMemory((PVOID)pConnList,BuffSize);
+
+ pConnList->ConnectionCount = Count;
+ // get the address of the Connection List buffer at the end of the
+ // structure so we can copy the Connection info into this area.
+ pCons = pConnList->ConnList;
+
+ pHead = &NbtConfig.AddressHead;
+ pEntry = pHead->Flink;
+ i = 0;
+ while (pEntry != pHead)
+ {
+ pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
+
+ pEntry = pEntry->Flink;
+
+ CTESpinLock(pAddressEle,OldIrq2);
+ pHead1 = &pAddressEle->ClientHead;
+ pEntry1 = pHead1->Flink;
+ while (pEntry1 != pHead1)
+ {
+ pClient = CONTAINING_RECORD(pEntry1,tCLIENTELE,Linkage);
+ pEntry1 = pEntry1->Flink;
+
+ CTESpinLock(pClient,OldIrq3);
+ pHead2 = &pClient->ConnectActive;
+ pEntry2 = pHead2->Flink;
+ while (pEntry2 != pHead2)
+ {
+ // count the connections in use
+ pConnEle = CONTAINING_RECORD(pEntry2,tCONNECTELE,Linkage);
+ CTEMemCopy(pCons->LocalName,
+ pConnEle->pClientEle->pAddress->pNameAddr->Name,
+ NETBIOS_NAME_SIZE);
+
+ pLowerConn = pConnEle->pLowerConnId;
+ if (pLowerConn)
+ {
+ pCons->SrcIpAddr = pLowerConn->SrcIpAddr;
+ pCons->Originator = (UCHAR)pLowerConn->bOriginator;
+#ifndef VXD
+ pCons->BytesRcvd = *(PLARGE_INTEGER)&pLowerConn->BytesRcvd;
+ pCons->BytesSent = *(PLARGE_INTEGER)&pLowerConn->BytesSent;
+#else
+ pCons->BytesRcvd = pLowerConn->BytesRcvd;
+ pCons->BytesSent = pLowerConn->BytesSent;
+#endif
+
+ CTEMemCopy(pCons->RemoteName,pConnEle->RemoteName,NETBIOS_NAME_SIZE);
+ }
+
+ pCons->State = pConnEle->state;
+ i++;
+ pCons++;
+
+ pEntry2 = pEntry2->Flink;
+ if (i == Count)
+ {
+ break;
+ }
+ }
+ if (i == Count)
+ {
+ CTESpinFree(pClient,OldIrq3);
+ break;
+ }
+
+ //
+ // now for the Listens
+ //
+ pHead2 = &pClient->ListenHead;
+ pEntry2 = pHead2->Flink;
+ while (pEntry2 != pHead2)
+ {
+ tLISTENREQUESTS *pListenReq;
+
+ // count the connections listening
+ pListenReq = CONTAINING_RECORD(pEntry2,tLISTENREQUESTS,Linkage);
+ pConnEle = (tCONNECTELE *)pListenReq->pConnectEle;
+
+ CTEMemCopy(pCons->LocalName,
+ pConnEle->pClientEle->pAddress->pNameAddr->Name,
+ NETBIOS_NAME_SIZE);
+
+ pCons->State = LISTENING;
+
+ i++;
+ pCons++;
+ pEntry2 = pEntry2->Flink;
+ if (i == Count)
+ {
+ break;
+ }
+ }
+ CTESpinFree(pClient,OldIrq3);
+ if (i == Count)
+ {
+ break;
+ }
+ }
+
+ CTESpinFree(pAddressEle,OldIrq2);
+ if (i == Count)
+ {
+ break;
+ }
+ }
+
+ //
+ // return the ptr to this wonderful structure of goodies
+ //
+ *ppConnList = (PVOID)pConnList;
+ *pSize = BuffSize;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ return fOverFlow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS ;
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtResyncRemoteCache(
+ )
+/*++
+
+Routine Description
+
+ This routine creates a list of netbios connections and returns them to the
+ client. It is used by the "NbtStat" console application.
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ tTIMERQENTRY TimerEntry;
+ LONG i;
+ LONG lRetcode;
+
+ CTEPagedCode();
+ //
+ // calling this routine N+1 times should remove all names from the remote
+ // hash table - N to count down the TimedOutCount to zero and then
+ // one more to remove the name
+ //
+ for (i=0;i < NbtConfig.RemoteTimeoutCount+1;i++ )
+ {
+ RemoteHashTimeout(NULL,NULL,&TimerEntry);
+ }
+
+ // now remove any preloaded entries
+ RemovePreloads();
+
+ // now reload the preloads
+ lRetcode = PrimeCache(NbtConfig.pLmHosts,
+ NULL,
+ TRUE,
+ NULL);
+#ifdef VXD
+ //
+ // check if things didn't go well (InDos was set etc.)
+ //
+ if (lRetcode == -1)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+#endif
+
+ return(STATUS_SUCCESS);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtQueryBcastVsWins(
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT PVOID *ppBuffer,
+ IN OUT PLONG pSize
+ )
+/*++
+
+Routine Description
+
+ This routine creates a list of netbios names that have been resolved
+ via broadcast and returns them along with the count of names resolved
+ via WINS and via broadcast. It lets a user know which names are not
+ in WINS and the relative frequency of "misses" with WINS that resort
+ to broadcast.
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ tNAMESTATS_INFO *pStats;
+ LONG Count;
+ tNAME *pDest;
+ tNAME *pSrc;
+ LONG Index;
+
+ //
+ // Is our status buffer size greater then the user's buffer?
+ //
+ if ( sizeof(tNAMESTATS_INFO) > *pSize )
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pStats = NbtAllocMem(sizeof(tNAMESTATS_INFO),NBT_TAG('Q'));
+ if ( !pStats )
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+
+ // Fill out the adapter status structure with zeros first
+ CTEZeroMemory((PVOID)pStats,sizeof(tNAMESTATS_INFO));
+
+ CTEMemCopy(pStats,&NameStatsInfo,FIELD_OFFSET(tNAMESTATS_INFO,NamesReslvdByBcast) );
+
+ //
+ // re-order the names so that names are returned in a list of newest to
+ // oldest down the list.
+ //
+ Count = 0;
+ Index = NameStatsInfo.Index;
+ pDest = &pStats->NamesReslvdByBcast[SIZE_RESOLVD_BY_BCAST_CACHE-1];
+
+ while (Count < SIZE_RESOLVD_BY_BCAST_CACHE)
+ {
+ pSrc = &NameStatsInfo.NamesReslvdByBcast[Index++];
+
+ CTEMemCopy(pDest,pSrc,NETBIOS_NAME_SIZE);
+
+ pDest--;
+ if (Index >= SIZE_RESOLVD_BY_BCAST_CACHE)
+ {
+ Index = 0;
+ pSrc = NameStatsInfo.NamesReslvdByBcast;
+ }
+ else
+ pSrc++;
+
+ Count++;
+ }
+
+ //
+ // return the ptr to this wonderful structure of goodies
+ //
+ *ppBuffer = (PVOID)pStats;
+ *pSize = sizeof(tNAMESTATS_INFO);
+
+ return STATUS_SUCCESS;
+
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtNewDhcpAddress(
+ tDEVICECONTEXT *pDeviceContext,
+ ULONG IpAddress,
+ ULONG SubnetMask)
+
+/*++
+
+Routine Description:
+
+ This routine processes a DHCP request to set a new ip address
+ for this node. Dhcp may pass in a zero for the ip address first
+ meaning that it is about to change the IP address, so all connections
+ should be shut down.
+ It closes all connections with the transport and all addresses. Then
+ It reopens them at the new ip address.
+
+Arguments:
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ NTSTATUS status;
+ LIST_ENTRY LowerConnFreeHead;
+ CTEULONGLONG AdapterNumber;
+ ULONG DeviceIndex;
+ BOOLEAN Attached;
+ ULONG Count;
+ BOOLEAN times = FALSE;
+
+ CTEPagedCode();
+
+ // grab the resource that synchronizes opening addresses and connections.
+ // to prevent the client from doing anything for a while
+ //
+ CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
+
+ if (IpAddress == 0)
+ {
+
+ if (pDeviceContext->IpAddress)
+ {
+ //
+ // The permanent name is a function of the MAC address so remove
+ // it since the Adapter is losing its Ip address
+ //
+ NbtRemovePermanentName(pDeviceContext);
+ //
+ // Dhcp is has passed down a null IP address meaning that it has
+ // lost the lease on the previous address, so close all connections
+ // to the transport - pLowerConn.
+ //
+ DisableInboundConnections(pDeviceContext,&LowerConnFreeHead);
+
+ NbtConfig.DhcpNumConnections = (USHORT)CloseLowerConnections(&LowerConnFreeHead);
+
+ CHECK_PTR(pDeviceContext);
+ pDeviceContext->IpAddress = 0;
+ }
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ CloseAddressesWithTransport(pDeviceContext);
+
+ // these are passed into here in the reverse byte order
+ //
+ IpAddress = htonl(IpAddress);
+ SubnetMask = htonl(SubnetMask);
+ //
+ // must be a new IP address, so open up the connections.
+ //
+ // get the ip address and open the required address
+ // objects with the underlying transport provider
+ // shift the adapter number once to get an index since the first
+ // adapter has an adapter number of 000001
+ //
+ AdapterNumber = pDeviceContext->AdapterNumber >> 1;
+
+ CTEAttachFsp(&Attached);
+
+ DeviceIndex = 0;
+ //
+ // shift the adapter number down till zero to get the index for the
+ // current adapter
+ //
+ while ( AdapterNumber )
+ {
+ DeviceIndex++;
+ AdapterNumber = AdapterNumber >> 1;
+ }
+
+ Count = CountUpperConnections(pDeviceContext);
+ Count += NBT_NUM_INITIAL_CONNECTIONS;
+
+retry:
+ status = NbtCreateAddressObjects(
+ IpAddress,
+ SubnetMask,
+ pDeviceContext);
+
+ if (!NT_SUCCESS(status))
+ {
+ CTEDetachFsp(Attached);
+ NbtLogEvent(EVENT_NBT_CREATE_ADDRESS,status);
+
+ KdPrint(("Failed to create the Address Objects after a new DHCP address, status=%X\n",status));
+ KdPrint(("IpAddress: %lx, SubnetMask: %lx, pDeviceContext: %lx\n", IpAddress, SubnetMask, pDeviceContext));
+
+ ASSERT(FALSE);
+
+ if (!times) {
+ KdPrint(("Retrying...\n"));
+ times = TRUE;
+ CTEAttachFsp(&Attached);
+ goto retry;
+ }
+ }
+ else
+ {
+
+ status = NbtInitConnQ(&pDeviceContext->LowerConnFreeHead,
+ 0, // not used
+ Count,
+ pDeviceContext);
+
+ if (!NT_SUCCESS(status))
+ {
+ NbtLogEvent(EVENT_NBT_CREATE_CONNECTION,status);
+ KdPrint(("Failed to create the Connections after a new DHCP address, status=%X\n",status));
+ }
+ }
+
+ CTEDetachFsp(Attached);
+
+ }
+
+ CTEExReleaseResource(&NbtConfig.Resource);
+
+ return(status);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtDereferenceClient(
+ IN tCLIENTELE *pClientEle
+ )
+/*++
+
+Routine Description
+
+ This routine deletes a client element record (which points to a name
+ in the local hash table. If this is the last client element hooked to that
+ name then the name is deleted too - causing a name release to be sent out.
+
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ CTELockHandle OldIrq2;
+ tADDRESSELE *pAddress;
+ PIRP pIrp;
+ NTSTATUS status;
+ tNAMEADDR *pNameAddr;
+ CTEULONGLONG AdapterNumber;
+
+ // lock the JointLock
+ // so we can delete the client knowing that no one has a spin lock
+ // pending on the client - basically use the Joint spin lock to
+ // coordinate access to the AddressHead - NbtConnectionList also locks
+ // the JointLock to scan the AddressHead list
+ //
+ ASSERT(pClientEle->RefCount);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq2);
+ if (--pClientEle->RefCount)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+ // return pending because we haven't been able to close the client
+ // completely yet
+ //
+ return(STATUS_PENDING);
+ }
+
+ //
+ // Unlink the Client in this routine after the reference count has
+ // gone to zero since the DgramRcv code may need to find the client in
+ // the Address client list when it is distributing a single received
+ // dgram to several clients.
+ //
+ RemoveEntryList(&pClientEle->Linkage);
+
+ pAddress = pClientEle->pAddress;
+
+ pIrp = pClientEle->pIrp;
+
+ //
+ // The browser may want to release a name on a single netcard so this
+ // check removes one of the adapter mask bits from pNameAddr if there
+ // are currently more than one there. If there is only one then the name
+ // will get released when all clients drop the name. In addition, only
+ // allow this if only one client has registered the name on each card.
+ //
+ // 5/23/95: this logic applies not just to the browser name, but any name
+ //
+ pNameAddr = pAddress->pNameAddr;
+ AdapterNumber = pClientEle->pDeviceContext->AdapterNumber;
+
+ if (((pNameAddr->AdapterMask & ~AdapterNumber) != 0 ) &&
+ (pAddress->MultiClients == FALSE) )
+ // (pNameAddr->Name[NETBIOS_NAME_SIZE-1] == 0x1d) )
+ {
+ pNameAddr->AdapterMask &= ~pClientEle->pDeviceContext->AdapterNumber;
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq2);
+
+ //
+ // The Connection Q Should be Empty otherwise we shouldn't get to this routine
+ //
+ ASSERT(IsListEmpty(&pClientEle->ConnectActive));
+ ASSERT(IsListEmpty(&pClientEle->ConnectHead));
+ ASSERT(IsListEmpty(&pClientEle->ListenHead));
+
+ // the Datagram Q should be empty otherwise we shouldn't be able to get
+ // to this routine.
+ ASSERT(IsListEmpty(&pClientEle->SndDgrams));
+
+
+ //
+ // check if there are more clients attached to the address, or can we
+ // delete the address too.
+ //
+ //
+ // It is possible that the address is null if the OpenAddress fails to
+ // send for some reason. In this case just skip the dereferenceAddress.
+ //
+ status = STATUS_SUCCESS;
+ if (pAddress)
+ {
+ status = NbtDereferenceAddress(pAddress);
+ }
+
+ // CHANGED:
+ // Do not hold up the client's irp until the name has released on the
+ // net. It is simpler to just complete it now
+ //
+
+ //
+ // free the memory associated with the client element
+ //
+ CTEMemFree((PVOID)pClientEle);
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("NBt: Delete Client Object %X\n",pClientEle));
+ //
+ // if their is a client irp, complete now. When the permanent name is
+ // released there is no client irp.
+ //
+ if (pIrp)
+ {
+
+ // complete the client's close address irp
+ CTEIoComplete(pIrp,STATUS_SUCCESS,0);
+
+ }
+ //
+ // this status insures that driver.c does not complete the irp too since
+ // it is completed above.
+ //
+ return(STATUS_PENDING);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtDereferenceAddress
+(
+ IN tADDRESSELE *pAddress
+ )
+/*++
+
+Routine Description
+
+ This routine deletes an Address element record (which points to a name
+ in the local hash table). A name release is sent on the wire for this name.
+
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ COMPLETIONCLIENT *pClientCompletion;
+ PVOID pTimerContext;
+ USHORT uAddrType;
+ ULONG SaveState;
+
+ // lock the hash table so another client cannot add a reference to this
+ // name before we delete it. We need the JointLock to keep the name
+ // refresh mechanism from finding the name in the list just as
+ // we are about to remove it (i.e. to synchronize with the name refresh
+ // code).
+ //
+ ASSERT(pAddress->RefCount);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ CTESpinLock(pAddress,OldIrq);
+ if (--pAddress->RefCount)
+ {
+ CTESpinFree(pAddress,OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_SUCCESS);
+ }
+
+ CTESpinFree(pAddress,OldIrq);
+
+
+
+ // The ClientHead should be empty otherwise we shouldn't get to this routine
+ //
+ ASSERT(IsListEmpty(&pAddress->ClientHead));
+ ASSERT(pAddress->pNameAddr->Verify == LOCAL_NAME);
+
+#if !defined(VXD) && DBG
+ if (pAddress->pNameAddr->Verify != LOCAL_NAME)
+ {
+ DbgBreakPoint();
+ }
+#endif
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("NbtDereferenceAddress - Freeing address object for %15.15s<%X>\n",
+ pAddress->pNameAddr->Name,pAddress->pNameAddr->Name[NETBIOS_NAME_SIZE-1] ));
+
+ //
+ // change the name state in the hash table until it is released
+ //
+ SaveState = pAddress->pNameAddr->NameTypeState;
+ pAddress->pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pAddress->pNameAddr->NameTypeState |= STATE_CONFLICT;
+
+ //
+ // check for any timers outstanding against the hash table entry - there shouldn't
+ // be any timers though
+ //
+ pClientCompletion = NULL;
+ ASSERT(!pAddress->pNameAddr->pTimer);
+ if (pAddress->pNameAddr->pTimer)
+ {
+ status = StopTimer(pAddress->pNameAddr->pTimer,
+ pClientCompletion,
+ &pTimerContext);
+
+ }
+
+ //
+ // Release name on the network
+ //
+ if ((pAddress->pNameAddr->NameTypeState & NAME_TYPE_MASK) != NAMETYPE_UNIQUE)
+ {
+ uAddrType = NBT_GROUP;
+ }
+ else
+ uAddrType = NBT_UNIQUE;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // only release the name on the net if it was not in conflict first
+ // This prevents name releases going out for names that were not actually
+ // claimed. Also, quick add names are not released on the net either.
+ //
+ if (!(SaveState & (STATE_CONFLICT | NAMETYPE_QUICK)) &&
+ (pAddress->pNameAddr->Name[0] != '*'))
+ {
+ status = ReleaseNameOnNet(pAddress->pNameAddr,
+ NbtConfig.pScope,
+ pAddress,
+ NameReleaseDone,
+ NodeType,
+ NULL);
+ // so the caller waits for the release to complete.
+ //
+ if (NT_SUCCESS(status))
+ {
+ return(STATUS_PENDING);
+ }
+ }
+
+ //
+ // set this to zero to prevent sending a name release on another adapter
+ // since we just want to complete the free the nameaddr here.
+ //
+ CHECK_PTR(pAddress->pNameAddr);
+ pAddress->pNameAddr->AdapterMask = 0;
+
+ NameReleaseDone((PVOID)pAddress,STATUS_SUCCESS);
+
+ //
+ // the name has been deleted, so return success
+ //
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+LockedDereferenceName(
+ IN tNAMEADDR *pNameAddr
+ )
+/*++
+
+Routine Description
+
+ This routine grabs the spin lock and dereferences the name.
+
+Arguments:
+
+ pNameAddr -ptr to name address structure.
+
+Return Values:
+
+ none.
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ NbtDereferenceName(pNameAddr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NbtDereferenceName(
+ IN tNAMEADDR *pNameAddr
+ )
+/*++
+
+Routine Description
+
+ This routine dereferences and possibly deletes a name element record by first unlinking from the
+ list it is in, and then freeing the memory if it is a local name. Remote
+ names remain in a circular list for reuse. The JOINTLOCK must be taken
+ before calling this routine.
+
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+
+{
+
+// GRAB THE SPIN LOCK BEFORE CALLING THIS ROUTINE!!
+
+ ASSERT(pNameAddr->RefCount);
+ if (--pNameAddr->RefCount > 0)
+ {
+ return;
+ }
+
+ //
+ // remove from the hash table
+ //
+ RemoveEntryList(&pNameAddr->Linkage);
+
+ if (pNameAddr->Verify == REMOTE_NAME)
+ {
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Freeing Remote Name Memory, %16.16s<%X> %X\n",
+ pNameAddr->Name,pNameAddr->Name[15],pNameAddr));
+
+ ASSERT(pNameAddr->Verify == REMOTE_NAME);
+ //
+ // if it is an internet group name it has a list of ip addresses and that
+ // memory block must be deleted
+ //
+ if (pNameAddr->NameTypeState & NAMETYPE_INET_GROUP)
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Freeing Internet Group Name Memory\n"));
+ CTEMemFree((PVOID)pNameAddr->pIpList);
+ }
+
+ }
+ else
+ {
+
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Freeing Local Name Memory, %16.16s<%X> %X\n",
+ pNameAddr->Name,pNameAddr->Name[15],pNameAddr));
+ ASSERT(pNameAddr->Verify == LOCAL_NAME);
+
+ }
+
+ if ( (pNameAddr->NameTypeState & NAMETYPE_INET_GROUP) == 0 )
+ {
+ if (pNameAddr->pIpAddrsList)
+ {
+ CTEMemFree((PVOID)pNameAddr->pIpAddrsList);
+ }
+ }
+
+ //
+ // free the memory now
+ //
+ CTEMemFree((PVOID)pNameAddr);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtDereferenceConnection(
+ IN tCONNECTELE *pConnEle
+ )
+/*++
+
+Routine Description
+
+ This routine dereferences and possibly deletes a connection element record.
+
+
+Arguments:
+
+
+Return Values:
+
+ TDI_STATUS - status of the request
+
+--*/
+{
+ CTELockHandle OldIrq;
+ PCTE_IRP pIrp;
+
+ // grab the lock of the item that contains the one we are trying to
+ // dereference and possibly delete. This prevents anyone from incrementing
+ // the count in between decrementing it and checking it for zero and deleting
+ // it if it is zero.
+
+ CTESpinLock(pConnEle,OldIrq);
+ ASSERT( (pConnEle->Verify == NBT_VERIFY_CONNECTION) ||
+ (pConnEle->Verify == NBT_VERIFY_CONNECTION_DOWN)) ;
+ ASSERT( pConnEle->RefCount > 0 ) ; // Check for too many derefs
+
+ CHECK_PTR(pConnEle);
+ if (--pConnEle->RefCount > 0)
+ {
+
+ CTESpinFree(pConnEle,OldIrq);
+ return(STATUS_PENDING);
+
+ }
+#ifndef VXD
+ IoFreeMdl(pConnEle->pNewMdl);
+ //
+ // Clear the context value in the Fileobject so that if this connection
+ // is used again (erroneously) it will not pass the VerifyHandle test
+ //
+ if (pConnEle->pIrpClose)
+ {
+ NTClearFileObjectContext(pConnEle->pIrpClose);
+ }
+#endif
+
+ // the close irp should be held in here
+ pIrp = pConnEle->pIrpClose;
+
+ CTESpinFree(pConnEle,OldIrq);
+
+ // The connection was unlinked from the ConnectHead or ConnectActive
+ // in the Cleanup routine, so no need to unlink again here
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("NBt: Delete Connection Object %X\n",pConnEle));
+
+ ASSERT((pConnEle->state <= NBT_CONNECTING) ||
+ (pConnEle->state > NBT_DISCONNECTING));
+
+#ifdef VXD
+ DbgPrint("NbtDereferenceConnection: Deleting Connecte element - 0x") ;
+ DbgPrintNum( (ULONG) pConnEle ) ; DbgPrint("\r\n") ;
+#endif
+
+ // free the memory block associated with the conn element
+ FreeConnectionObj(pConnEle);
+
+ // The client may have sent down a close before NBT was done with the
+ // pConnEle, so Pending was returned and the irp stored in the pCOnnEle
+ // structure. Now that the structure is fully dereferenced, we can
+ // return the irp.
+ if (pIrp)
+ {
+ CTEIoComplete(pIrp,STATUS_SUCCESS,0);
+ }
+ return(STATUS_PENDING);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NbtDereferenceLowerConnection(
+ IN tLOWERCONNECTION *pLowerConn
+ )
+/*++
+Routine Description:
+
+ This Routine decrements the reference count on a Lower Connection element and
+ if the value is zero, deletes the connection.
+
+Arguments:
+
+Return Value:
+
+ NONE
+
+--*/
+
+{
+ CTELockHandle OldIrq1;
+ tDEVICECONTEXT *pDeviceContext;
+ NTSTATUS status;
+
+ pDeviceContext = pLowerConn->pDeviceContext;
+
+ CTESpinLock(pLowerConn,OldIrq1);
+
+ ASSERT(pLowerConn->RefCount);
+
+ if(--pLowerConn->RefCount == 0)
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("NBt: Delete Lower Connection Object %X\n",pLowerConn));
+
+ //
+ // it's possible that transport may indicate before we run the code
+ // in WipeOutLowerconn. If that happens, we don't want to run this
+ // code again ( which will queue this to worker thread again!)
+ // So, bump it up to some large value
+ //
+ pLowerConn->RefCount = 1000;
+
+ CTESpinFree(pLowerConn,OldIrq1);
+
+ //
+ // let's come back and do this later since we may be at dpc now
+ //
+ CTEQueueForNonDispProcessing(
+ NULL,
+ pLowerConn,
+ NULL,
+ WipeOutLowerconn,
+ pLowerConn->pDeviceContext);
+ }
+ else
+ CTESpinFree(pLowerConn,OldIrq1);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtDeleteLowerConn(
+ IN tLOWERCONNECTION *pLowerConn
+ )
+/*++
+Routine Description:
+
+ This Routine attempts to delete a lower connection by closing it with the
+ transport and dereferencing it.
+
+Arguments:
+
+Return Value:
+
+ NONE
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ tDEVICECONTEXT *pDeviceContext;
+
+
+ status = STATUS_SUCCESS;
+
+ // remove the lower connection from the active queue and then
+ // delete it
+ //
+ pDeviceContext = pLowerConn->pDeviceContext;
+
+ CTESpinLock(pDeviceContext,OldIrq);
+
+ //
+ // The lower conn can get removed from the inactive list in OutOfRsrcKill (when we queue it on
+ // the OutofRsrc.ConnectionHead). Check the flag that indicates this connection was dequed then.
+ //
+ if (!pLowerConn->OutOfRsrcFlag) {
+ RemoveEntryList(&pLowerConn->Linkage);
+ }
+
+ pLowerConn->Linkage.Flink = pLowerConn->Linkage.Blink = (struct _LIST_ENTRY * volatile)0x00009789;
+
+ CTESpinFree(pDeviceContext,OldIrq);
+
+ NbtDereferenceLowerConnection(pLowerConn);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+WipeOutLowerconn(
+ IN PVOID pContext
+ )
+/*++
+Routine Description:
+
+ This routine does all the file close etc. that we couldn't do at dpc level
+ and then frees the memory.
+
+Arguments:
+
+ pLowerConn - the lower connection to be wiped out
+
+Return Value:
+
+ NONE
+
+--*/
+
+{
+
+ tLOWERCONNECTION *pLowerConn;
+ PVOID pIndicate;
+
+
+ pLowerConn = (tLOWERCONNECTION*)((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
+
+ // dereference the fileobject ptr
+ NTDereferenceObject((PVOID *)pLowerConn->pFileObject);
+
+ // close the lower connection with the transport
+#ifndef VXD
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Closing Handle %X -> %X\n",pLowerConn,pLowerConn->FileHandle));
+#else
+ KdPrint(("Nbt:Closing Handle %X -> %X\n",pLowerConn,pLowerConn->pFileObject));
+#endif
+
+ NbtTdiCloseConnection(pLowerConn);
+
+ // Close the Address object too since outbound connections use unique
+ // addresses for each connection, whereas inbound connections all use
+ // the same address ( and we don't want to close that address ever ).
+ if (pLowerConn->pAddrFileObject)
+ {
+ // dereference the fileobject ptr
+ NTDereferenceObject((PVOID *)pLowerConn->pAddrFileObject);
+
+ NbtTdiCloseAddress(pLowerConn);
+ }
+
+#ifndef VXD
+ // free the indicate buffer and the mdl that holds it
+ //
+ pIndicate = MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl);
+
+ CTEMemFree(pIndicate);
+ IoFreeMdl(pLowerConn->pIndicateMdl);
+#endif
+
+ // now free the memory block tracking this connection
+ CTEMemFree((PVOID)pLowerConn);
+
+ CTEMemFree(pContext);
+
+}
diff --git a/private/ntos/nbt/nbt/namesrv.c b/private/ntos/nbt/nbt/namesrv.c
new file mode 100644
index 000000000..1c46a7b6a
--- /dev/null
+++ b/private/ntos/nbt/nbt/namesrv.c
@@ -0,0 +1,3886 @@
+ /*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Namesrv.c
+
+Abstract:
+
+ This file contains the name service functions called by other parts of
+ the NBT code. (QueryNameOnNet, FindName, RegisterName). It also contains
+ the completion routines for the timeouts associated with these functions.
+
+ The pScope values that are passed around from one routine to the next
+ point to the scope string for the name. If there is no scope then the
+ pScope ptr points at a single character '\0' - signifying a string of
+ zero length. Therefore the check for scope is "if (*pScope != 0)"
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+
+//
+// function prototypes for completion routines that are local to this file
+//
+NTSTATUS
+AddToPendingList(
+ IN PCHAR pName,
+ OUT tNAMEADDR **ppNameAddr
+ );
+VOID
+MSnodeCompletion(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+VOID
+MSnodeRegCompletion(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+
+VOID
+SetWinsDownFlag(
+ tDEVICECONTEXT *pDeviceContext
+ );
+
+VOID
+ReleaseCompletion(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+
+VOID
+NextRefresh(
+ IN PVOID pNameAdd,
+ IN NTSTATUS status
+ );
+VOID
+NextRefreshNonDispatch(
+ IN PVOID pContext
+ );
+VOID
+GetNextName(
+ IN tNAMEADDR *pNameAddrIn,
+ OUT tNAMEADDR **ppNameAddr
+ );
+
+NTSTATUS
+StartRefresh(
+ IN tNAMEADDR *pNameAddr,
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN BOOLEAN ResetDevice
+ );
+
+VOID
+RefreshBegin(
+ PVOID pContext
+ );
+VOID
+NextKeepAlive(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN NTSTATUS statuss,
+ IN ULONG Info
+ );
+VOID
+GetNextKeepAlive(
+ tDEVICECONTEXT *pDeviceContext,
+ tDEVICECONTEXT **ppDeviceContextOut,
+ tLOWERCONNECTION *pLowerConnIn,
+ tLOWERCONNECTION **ppLowerConnOut
+ );
+VOID
+SessionKeepAliveNonDispatch(
+ PVOID pContext
+ );
+VOID
+WinsDownTimeout(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+
+BOOL
+AppropriateNodeType(
+ IN PCHAR pName,
+ IN ULONG NodeType
+ );
+
+BOOL
+IsBrowserName(
+ IN PCHAR pName
+ );
+
+#if DBG
+unsigned char Buff[256];
+unsigned char Loc;
+#endif
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, SessionKeepAliveNonDispatch)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//----------------------------------------------------------------------------
+ tNAMEADDR *
+FindName(
+ enum eNbtLocation Location,
+ PCHAR pName,
+ PCHAR pScope,
+ USHORT *pRetNameType
+ )
+/*++
+
+Routine Description:
+
+ This routine searches the name table to find a name. The table searched
+ depends on the Location passed in - whether it searches the local table
+ or the network names table. The routine checks the state of the name
+ and only returns names in the resolved state.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ tNAMEADDR *pNameAddr;
+ NTSTATUS status;
+ tHASHTABLE *pHashTbl;
+
+ if (Location == NBT_LOCAL)
+ {
+ pHashTbl = pNbtGlobConfig->pLocalHashTbl;
+ }
+ else
+ {
+ pHashTbl = pNbtGlobConfig->pRemoteHashTbl;
+
+ }
+ status = FindInHashTable(
+ pHashTbl,
+ pName,
+ pScope,
+ &pNameAddr);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(NULL);
+ }
+
+ *pRetNameType = (USHORT)pNameAddr->NameTypeState;
+
+
+ //
+ // Only return names that are in the resolved state
+ //
+ if (!(pNameAddr->NameTypeState & STATE_RESOLVED))
+ {
+ pNameAddr = NULL;
+ }
+
+ return(pNameAddr);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+AddToPendingList(
+ IN PCHAR pName,
+ OUT tNAMEADDR **ppNameAddr
+ )
+/*++
+Routine Description:
+
+ This routine Adds a name query request to the PendingNameQuery list.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+{
+ tNAMEADDR *pNameAddr;
+
+ pNameAddr = NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('R'));
+ if (pNameAddr)
+ {
+ CTEZeroMemory(pNameAddr,sizeof(tNAMEADDR));
+
+ CTEMemCopy(pNameAddr->Name,pName,NETBIOS_NAME_SIZE);
+ pNameAddr->NameTypeState = STATE_RESOLVING | NBT_UNIQUE;
+ pNameAddr->RefCount = 1;
+ pNameAddr->Verify = REMOTE_NAME;
+ pNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
+
+ InsertTailList(&NbtConfig.PendingNameQueries,
+ &pNameAddr->Linkage);
+
+ *ppNameAddr = pNameAddr;
+ return(STATUS_SUCCESS);
+ }
+ else
+ return(STATUS_INSUFFICIENT_RESOURCES);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+QueryNameOnNet(
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN ULONG IpAddress,
+ IN USHORT uType,
+ IN PVOID pClientContext,
+ IN PVOID pClientCompletion,
+ IN ULONG LocalNodeType,
+ IN tNAMEADDR *pNameAddrIn,
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT tDGRAM_SEND_TRACKING **ppTracker,
+ IN CTELockHandle *pJointLockOldIrq
+ )
+/*++
+
+Routine Description:
+
+ This routine attempts to resolve a name on the network either by a
+ broadcast or by talking to the NS depending on the type of node. (M,P or B)
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+Called By: ProxyQueryFromNet() in proxy.c, NbtConnect() in name.c
+
+--*/
+
+{
+ ULONG Timeout;
+ USHORT Retries;
+ NTSTATUS status;
+ PVOID pCompletionRoutine;
+ tDGRAM_SEND_TRACKING *pSentList;
+ tNAMEADDR *pNameAddr;
+ LPVOID pContext2 = NULL;
+ CHAR cNameType = pName[NETBIOS_NAME_SIZE-1];
+ BOOL SendFlag = TRUE;
+ LONG IpAddr = 0;
+
+ status = GetTracker(&pSentList);
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+ if (ppTracker)
+ {
+ *ppTracker = pSentList;
+ }
+
+ // set to NULL to catch any erroneous frees.
+ CHECK_PTR(pSentList);
+ pSentList->SendBuffer.pDgramHdr = NULL;
+ pSentList->pDeviceContext = pDeviceContext;
+
+ //
+ // put the name in the remote cache to keep track of it while it resolves...
+ //
+ pNameAddr = NULL;
+ if (!pNameAddrIn)
+ {
+ status = AddToPendingList(pName,&pNameAddr);
+
+ if (!NT_SUCCESS(status))
+ {
+ FreeTracker(pSentList,RELINK_TRACKER);
+ return(status);
+ }
+
+ // fill in the record with the name and IpAddress
+ pNameAddr->NameTypeState = (uType == NBT_UNIQUE) ?
+ NAMETYPE_UNIQUE : NAMETYPE_GROUP;
+ }
+ else
+ {
+ status = STATUS_SUCCESS;
+ pNameAddr = pNameAddrIn;
+ pNameAddr->RefCount = 1;
+ }
+
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= STATE_RESOLVING;
+ pNameAddr->Ttl = NbtConfig.RemoteHashTimeout;
+
+#ifdef PROXY_NODE
+ //
+ // If the node type is PROXY, it means that the request is being sent
+ // as a result of hearing a name registration or a name query on the net.
+ //
+ // If the node type is not == PROXY (i.e. it is MSNODE | PROXY,
+ // PNODE | PROXY, MSNODE, PNODE, etc, then the request is being sent as
+ // a result of a client request
+ //
+ // Refer: RegOrQueryFromNet in Proxy.c
+ //
+ // This field is used in QueryFromNet() to determine whether or not
+ // to revert to Broadcast
+ //
+#endif
+ if(LocalNodeType & PROXY)
+ {
+ pNameAddr->fProxyReq = (BOOLEAN)TRUE;
+ }
+ else
+ {
+ pNameAddr->fProxyReq = (BOOLEAN)FALSE;
+ LocalNodeType = AppropriateNodeType( pName, LocalNodeType );
+ }
+
+ // keep a ptr to the Ascii name so that we can remove the name from the
+ // hash table later if the query fails.
+ pSentList->pNameAddr = pNameAddr;
+
+ //
+ // Set a few values as a precursor to registering the name either by
+ // broadcast or with the name server
+ //
+#ifdef PROXY_NODE
+ IF_PROXY(LocalNodeType)
+ {
+ Retries = (USHORT)pNbtGlobConfig->uNumRetries;
+ Timeout = (ULONG)pNbtGlobConfig->uRetryTimeout;
+ pCompletionRoutine = ProxyTimerComplFn;
+ pSentList->Flags = NBT_NAME_SERVER;
+ pContext2 = pClientContext;
+ pClientContext = NULL;
+
+ }
+ else
+#endif
+ {
+
+ Retries = pNbtGlobConfig->uNumRetries;
+ Timeout = (ULONG)pNbtGlobConfig->uRetryTimeout;
+ pCompletionRoutine = MSnodeCompletion;
+ pSentList->Flags = NBT_NAME_SERVER;
+
+ // use broadcast if no name server address for MSNODE or Wins down,
+ // or it is Bnode,Mnode.
+ // for Pnode, just allow it to do the name query on the loop back
+ // address
+ //
+ if ((LocalNodeType & (MNODE | BNODE)) ||
+ ((LocalNodeType & MSNODE) &&
+ ((pDeviceContext->lNameServerAddress == LOOP_BACK) ||
+ pDeviceContext->WinsIsDown)))
+ {
+ Retries = pNbtGlobConfig->uNumBcasts;
+ Timeout = (ULONG)pNbtGlobConfig->uBcastTimeout;
+ pSentList->Flags = NBT_BROADCAST;
+ }
+ else
+ if ((pDeviceContext->lNameServerAddress == LOOP_BACK) ||
+ pDeviceContext->WinsIsDown)
+ {
+ //
+ // short out timeout when no wins server configured -for PNODE
+ //
+ Retries = 1;
+ Timeout = 10;
+ pSentList->Flags = NBT_NAME_SERVER_BACKUP;
+ }
+
+ //
+ // no sense doing a name query out an adapter with no Ip address
+ //
+ if (
+ (pDeviceContext->IpAddress == LOOP_BACK)
+ || ( IpAddr = Nbt_inet_addr(pName) )
+ )
+ {
+
+ Retries = 1;
+ Timeout = 10;
+ pSentList->Flags = NBT_BROADCAST;
+ SendFlag = FALSE;
+ if (LocalNodeType & (PNODE | MNODE))
+ {
+ pSentList->Flags = NBT_NAME_SERVER_BACKUP;
+ }
+
+ }
+ }
+
+ //
+ // set the ref count high enough so that a pdu from the wire cannot
+ // free the tracker while UdpSendNsBcast is running - i.e. between starting
+ // the timer and actually sending the datagram.
+ //
+ pSentList->RefCount = 2;
+
+ //
+ // put a pointer to the tracker here so that other clients attempting to
+ // query the same name at the same time can tack their trackers onto
+ // the end of this one. - i.e. This is the tracker for the
+ // datagram send, or connect, not the name query.
+ //
+ pNameAddr->pTracker = pClientContext;
+
+ // do a name query... will always return status pending...
+ // the pNameAddr structure cannot get deleted out from under us since
+ // only a timeout on the send (3 retries) will remove the name. Any
+ // response from the net will tend to keep the name (change state to Resolved)
+ //
+ CHECK_PTR(pNameAddr);
+ pNameAddr->pTimer = NULL;
+ CTESpinFree(&NbtConfig.JointLock,*pJointLockOldIrq);
+
+ //
+ // Bug: 22542 - prevent broadcast of remote adapter status on net view of limited subnet b'cast address.
+ // In order to test for subnet broadcasts, we need to match against the subnet masks of all adapters. This
+ // is expensive and not done.
+ // Just check for the limited bcast.
+ //
+ if (IpAddr == 0xffffffff) {
+ KdPrint(("Nbt: Query on Limited broadcast - failed\n"));
+ status = STATUS_BAD_NETWORK_PATH;
+ } else {
+ status = UdpSendNSBcast(pNameAddr,
+ pScope,
+ pSentList,
+ pCompletionRoutine,
+ pClientContext,
+ pClientCompletion,
+ Retries,
+ Timeout,
+ eNAME_QUERY,
+ SendFlag);
+ }
+
+ // a successful send means, Don't complete the Irp. Status Pending is
+ // returned to ntisol.c to tell that code not to complete the irp. The
+ // irp will be completed when this send either times out or a response
+ // is heard. In the event of an error in the send, allow that return
+ // code to propagate back and result in completing the irp - i.e. if
+ // there isn't enough memory to allocate a buffer or some such thing
+ //
+ DereferenceTracker(pSentList);
+ CTESpinLock(&NbtConfig.JointLock,*pJointLockOldIrq);
+
+ if (NT_SUCCESS(status))
+ {
+ LOCATION(0x49);
+
+ // this return must be here to avoid freeing the tracker below.
+ status = STATUS_PENDING;
+ }
+ else
+ {
+ tTIMERQENTRY *pTimer;
+ COMPLETIONCLIENT pCompletion=NULL;
+
+ LOCATION(0x50);
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Query failed - bad retcode from UdpSendNsBcast = %X\n",
+ status));
+
+ pTimer = pNameAddr->pTimer;
+ CHECK_PTR(pNameAddr);
+ pNameAddr->pTimer = NULL;
+
+ // save this value for below.
+ pCompletion = pTimer->ClientCompletion;
+
+ // dereferencing the tracker no longer frees the dgram hdr too.
+ // if IP addr is limited bcast, then UdpSendNSBcast was not called.
+ if ((status != STATUS_INSUFFICIENT_RESOURCES) &&
+ (IpAddr != 0xffffffff))
+ {
+ CTEMemFree(pSentList->SendBuffer.pDgramHdr);
+ }
+
+ //
+ // UdpSendNsBcast cannot fail AND start the timer, therefore there
+ // is no need to worry about stopping the timer here.
+ //
+ {
+ // the timer was never started...
+ if (ppTracker)
+ {
+ *ppTracker = NULL;
+ }
+
+ //
+ // This will free the tracker
+ //
+ DereferenceTrackerNoLock(pSentList);
+ NbtDereferenceName(pNameAddr);
+ }
+ }
+
+ return(status);
+}
+//----------------------------------------------------------------------------
+ VOID
+MSnodeCompletion(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the timer code when the timer expires. It must
+ decide if another name query should be done, and if not, then it calls the
+ client's completion routine (in completion2).
+ This routine handles the broadcast portion of the name queries (i.e.
+ those name queries that go out as broadcasts).
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ COMPLETIONCLIENT pClientCompletion;
+ USHORT Flags;
+ tDGRAM_SEND_TRACKING *pClientTracker;
+ ULONG LocalNodeType;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ LocalNodeType = AppropriateNodeType( pTracker->pNameAddr->Name, NodeType );
+
+ //
+ // check if the client completion routine is still set. If not then the
+ // timer has been cancelled and this routine should just clean up its
+ // buffers associated with the tracker.
+ //
+ if (pTimerQEntry)
+ {
+
+ //
+ // to prevent a client from stopping the timer and deleting the
+ // pNameAddr, grab the lock and check if the timer has been stopped
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ ASSERT(pTracker->pNameAddr->Verify == REMOTE_NAME);
+#if !defined(VXD) && DBG
+ if (pTracker->pNameAddr->Verify != REMOTE_NAME)
+ {
+ DbgBreakPoint();
+ }
+#endif
+ if (pTimerQEntry->Flags & TIMER_RETIMED)
+ {
+ pTimerQEntry->Flags &= ~TIMER_RETIMED;
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ //
+ // if we are not bound to this card than use a very short timeout
+ //
+ if (!pTracker->pDeviceContext->pNameServerFileObject)
+ {
+ pTimerQEntry->DeltaTime = 10;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return;
+ }
+
+
+ pClientTracker = (tDGRAM_SEND_TRACKING *)pTimerQEntry->ClientContext;
+
+ //
+ // if the tracker has been cancelled, don't do any more queries
+ //
+ if (pClientTracker->Flags & TRACKER_CANCELLED)
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt: MSnodeCompletion: tracker flag cancelled\n"));
+
+ //
+ // In case the timer has been stopped, we coordinate
+ // through the pClientCompletionRoutine Value with StopTimer.
+ //
+ pClientCompletion = pTimerQEntry->ClientCompletion;
+
+ //
+ // remove from the PendingNameQueries list
+ //
+ RemoveEntryList(&pTracker->pNameAddr->Linkage);
+ InitializeListHead(&pTracker->pNameAddr->Linkage);
+
+ // remove the link from the name table to this timer block
+ CHECK_PTR(((tNAMEADDR *)pTimerQEntry->pCacheEntry));
+ ((tNAMEADDR *)pTimerQEntry->pCacheEntry)->pTimer = NULL;
+ //
+ // to synch. with the StopTimer routine, Null the client completion
+ // routine so it gets called just once.
+ //
+ CHECK_PTR(pTimerQEntry);
+ pTimerQEntry->ClientCompletion = NULL;
+
+ //
+ // remove the name from the hash table, since it did not
+ // resolve
+ //
+ CHECK_PTR(pTracker->pNameAddr);
+ pTracker->pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pTracker->pNameAddr->NameTypeState |= STATE_RELEASED;
+ pTracker->pNameAddr->pTimer = NULL;
+
+ NbtDereferenceName(pTracker->pNameAddr);
+ pTracker->pNameAddr = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // there can be a list of trackers Q'd up on this name
+ // query, so we must complete all of them!
+ //
+ CompleteClientReq(pClientCompletion,
+ pClientTracker,
+ STATUS_CANCELLED);
+
+ // return the tracker block to its queue
+ LOCATION(0x51);
+ DereferenceTracker(pTracker);
+
+ return;
+
+ }
+
+ if (pTimerQEntry->ClientCompletion)
+ {
+ // if number of retries is not zero then continue trying to contact the
+ // Name Server.
+ //
+ if (!(--pTimerQEntry->Retries))
+ {
+
+ // set the retry count again
+ //
+ pTimerQEntry->Retries = NbtConfig.uNumRetries;
+ Flags = pTracker->Flags;
+ pTracker->Flags &= ~(NBT_NAME_SERVER_BACKUP
+ | NBT_NAME_SERVER
+ | NBT_BROADCAST);
+
+ if ((Flags & NBT_BROADCAST) && (LocalNodeType & MNODE) &&
+ (pTracker->pDeviceContext->lNameServerAddress != LOOP_BACK) &&
+ !pTracker->pDeviceContext->WinsIsDown)
+ {
+ LOCATION(0x44);
+ // *** MNODE ONLY ***
+ //
+ // Can't Resolve through broadcast, so try the name server
+ //
+ pTracker->Flags |= NBT_NAME_SERVER;
+
+ // set a different timeout for name resolution through WINS
+ //
+ pTimerQEntry->DeltaTime = NbtConfig.uRetryTimeout;
+
+ }
+ else
+ if ((Flags & NBT_NAME_SERVER) && !(LocalNodeType & BNODE))
+ {
+ LOCATION(0x47);
+ // *** NOT BNODE ***
+ //
+ // Can't reach the name server, so try the backup
+ //
+ pTracker->Flags |= NBT_NAME_SERVER_BACKUP;
+ //
+ // short out the timeout if no backup name server
+ //
+ if ((pTracker->pDeviceContext->lBackupServer == LOOP_BACK) ||
+ pTracker->pDeviceContext->WinsIsDown)
+ {
+ pTimerQEntry->Retries = 1;
+ pTimerQEntry->DeltaTime = 10;
+
+ }
+
+ }
+ else
+ if ((Flags & NBT_NAME_SERVER_BACKUP)
+ && (LocalNodeType & MSNODE))
+ {
+ LOCATION(0x46);
+ // *** MSNODE ONLY ***
+ //
+ // Can't reach the name server(s), so try broadcast name queries
+ //
+ pTracker->Flags |= NBT_BROADCAST;
+
+ // set a different timeout for broadcast name resolution
+ //
+ pTimerQEntry->DeltaTime = NbtConfig.uBcastTimeout;
+ pTimerQEntry->Retries = NbtConfig.uNumBcasts;
+
+ //
+ // Set the WinsIsDown Flag and start a timer so we don't
+ // try wins again for 15 seconds or so...only if we failed
+ // to reach WINS, rather than WINS returning a neg response.
+ //
+ if (!(Flags & WINS_NEG_RESPONSE))
+ {
+ SetWinsDownFlag(pTracker->pDeviceContext);
+ }
+ }
+ else
+ {
+ BOOLEAN bFound = FALSE;
+ LOCATION(0x45);
+
+ //
+ // see if the name is in the lmhosts file, if it ISN'T the
+ // proxy making the name query request!!
+ //
+ status = STATUS_UNSUCCESSFUL;
+
+ //
+ // In case the timer has been stopped, we coordinate
+ // through the pClientCompletionRoutine Value with StopTimer.
+ //
+ pClientCompletion = pTimerQEntry->ClientCompletion;
+ //
+ // the timeout has expired on the broadcast name resolution
+ // so call the client
+ //
+
+ //
+ // remove from the PendingNameQueries list
+ //
+ RemoveEntryList(&pTracker->pNameAddr->Linkage);
+ InitializeListHead(&pTracker->pNameAddr->Linkage);
+
+ // remove the link from the name table to this timer block
+ CHECK_PTR(((tNAMEADDR *)pTimerQEntry->pCacheEntry));
+ ((tNAMEADDR *)pTimerQEntry->pCacheEntry)->pTimer = NULL;
+ //
+ // to synch. with the StopTimer routine, Null the client completion
+ // routine so it gets called just once.
+ //
+ CHECK_PTR(pTimerQEntry);
+ pTimerQEntry->ClientCompletion = NULL;
+
+
+ if ((NbtConfig.EnableLmHosts || NbtConfig.ResolveWithDns) &&
+ (!pTracker->pNameAddr->fProxyReq ))
+ {
+ // only do this if the client completion routine has not
+ // been run yet.
+ //
+ if (pClientCompletion)
+ {
+ status = LmHostQueueRequest(pTracker,
+ pTimerQEntry->ClientContext,
+ pClientCompletion,
+ ScanLmHostFile,
+ pTracker->pDeviceContext,
+ OldIrq);
+ }
+ }
+
+
+ CHECK_PTR(pTimerQEntry);
+ CHECK_PTR(pTimerQEntry->pCacheEntry);
+ if (NT_SUCCESS(status))
+ {
+ // if it is successfully queued to the Worker thread,
+ // then Null the ClientCompletion routine in the timerQ
+ // structure, letting
+ // the worker thread handle the rest of the name query
+ // resolution. Also null the timer ptr in the
+ // nameAddr entry in the name table.
+ //
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ }
+ else
+ {
+
+ pClientTracker = (tDGRAM_SEND_TRACKING *)pTimerQEntry->ClientContext;
+
+ //
+ // remove the name from the hash table, since it did not
+ // resolve
+ //
+ CHECK_PTR(pTracker->pNameAddr);
+ pTracker->pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pTracker->pNameAddr->NameTypeState |= STATE_RELEASED;
+ pTracker->pNameAddr->pTimer = NULL;
+
+ NbtDereferenceName(pTracker->pNameAddr);
+ pTracker->pNameAddr = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // there can be a list of trackers Q'd up on this name
+ // query, so we must complete all of them!
+ //
+ CompleteClientReq(pClientCompletion,
+ pClientTracker,
+ STATUS_TIMEOUT);
+
+ // return the tracker block to its queue
+ LOCATION(0x51);
+ DereferenceTracker(pTracker);
+ }
+
+ return;
+ }
+
+
+
+ }
+ LOCATION(0x48);
+ pTracker->RefCount++;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = UdpSendNSBcast(pTracker->pNameAddr,
+ NbtConfig.pScope,
+ pTracker,
+ NULL,NULL,NULL,
+ 0,0,
+ eNAME_QUERY,
+ TRUE);
+
+ DereferenceTracker(pTracker);
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ }
+ else
+ {
+ // return the tracker block to its queue
+ LOCATION(0x52);
+ DereferenceTrackerNoLock((tDGRAM_SEND_TRACKING *)pContext);
+ }
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SetWinsDownFlag(
+ tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the WinsIsDown flag if its not already set and
+ its not a Bnode. It starts a 15 second or so timer that un sets the
+ flag when it expires.
+
+ This routine must be called while holding the Joint Lock.
+
+Arguments:
+
+ None
+
+Return Value:
+ None
+
+--*/
+{
+ NTSTATUS status;
+ tTIMERQENTRY *pTimer;
+
+ if ((!pDeviceContext->WinsIsDown) && !(NodeType & BNODE))
+ {
+ status = StartTimer(NbtConfig.WinsDownTimeout,
+ pDeviceContext, // context value
+ NULL,
+ WinsDownTimeout,
+ NULL,
+ NULL,
+ 1, // retries
+ &pTimer
+ );
+ if (NT_SUCCESS(status))
+ {
+ pDeviceContext->WinsIsDown = TRUE;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+ VOID
+WinsDownTimeout(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the timer code when the timer expires.
+ It just sets the WinsIsDown boolean to False so that we will try WINS
+ again. In this way we will avoid talking to WINS during this timeout.
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)pContext;
+
+ pDeviceContext->WinsIsDown = FALSE;
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:WINS DOWN Timed Out - Up again\n"));
+
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+CompleteClientReq(
+ COMPLETIONCLIENT pClientCompletion,
+ tDGRAM_SEND_TRACKING *pTracker,
+ NTSTATUS status
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by completion routines to complete the client
+ request. It may involve completing several queued up requests.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tDGRAM_SEND_TRACKING *pTrack;
+ tDEVICECONTEXT *pDeviceContext;
+ CTELockHandle OldIrq;
+ LIST_ENTRY ListEntry;
+
+
+ //
+ // set up a new list head for any queued name queries.
+ // since we may need to do a new name query below.
+ // The Proxy hits this routine with a Null Tracker, so check for that.
+ //
+ pEntry = pHead = &ListEntry;
+ if (pTracker)
+ {
+ pDeviceContext = pTracker->pDeviceContext;
+ if( !IsListEmpty(&pTracker->TrackerList))
+ {
+ ListEntry.Flink = pTracker->TrackerList.Flink;
+ ListEntry.Flink->Blink = &ListEntry;
+ ListEntry.Blink = pTracker->TrackerList.Blink;
+ ListEntry.Blink->Flink = &ListEntry;
+
+ pHead = &ListEntry;
+ pEntry = pHead->Flink;
+ }
+ }
+
+
+ (*pClientCompletion)(pTracker,status);
+
+ while (pEntry != pHead)
+ {
+ pTrack = CONTAINING_RECORD(pEntry,tDGRAM_SEND_TRACKING,TrackerList);
+ pEntry = pEntry->Flink;
+
+ //
+ // if the name query failed and there is another requested queued on
+ // a different device context, re-attempt the name query
+ //
+ if ((pTrack->pDeviceContext != pDeviceContext) &&
+ (status != STATUS_SUCCESS))
+ {
+ //
+ // setup the correct back link since this guy is now the list
+ // head. The Flink is ok unless the list is empty now.
+ //
+ pTrack->TrackerList.Blink = ListEntry.Blink;
+ pTrack->TrackerList.Blink->Flink = &pTrack->TrackerList;
+
+ if (pTrack->TrackerList.Flink == &ListEntry)
+ {
+ pTrack->TrackerList.Flink = &pTrack->TrackerList;
+ }
+
+ // do a name query on the next name in the list
+ // and then wait for it to complete before processing any more
+ // names on the list.
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ status = QueryNameOnNet(
+ pTrack->pDestName,
+ NbtConfig.pScope,
+ 0, //no ip address yet.
+ NBT_UNIQUE, //use this as the default
+ (PVOID)pTrack,
+ pTrack->CompletionRoutine,
+ NodeType & NODE_MASK,
+ NULL,
+ pTrack->pDeviceContext,
+ NULL,
+ &OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ break;
+ }
+ else
+ {
+ //
+ // get the completion routine for this tracker since it may be
+ // different than the tracker tied to the timer block. i.e.
+ // pCompletionClient passed to this routine.
+ //
+ pClientCompletion = pTrack->CompletionRoutine;
+ (*pClientCompletion)(pTrack,status);
+
+ }
+
+
+ }
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtRegisterName(
+ IN enum eNbtLocation Location,
+ IN ULONG IpAddress,
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN PVOID pClientContext,
+ IN PVOID pClientCompletion,
+ IN USHORT uAddressType,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine registers a name from local or from the network depending
+ on the value of Location. (i.e. local node uses this routine as well
+ as the proxy code.. although it has only been tested with the local
+ node registering names so far - and infact the remote code has been
+ removed... since it is not used. All that remains is to remove
+ the Location parameter.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ ULONG Timeout;
+ USHORT Retries;
+ PVOID pCompletionRoutine;
+ NTSTATUS status;
+ tNAMEADDR *pNameAddr;
+ USHORT uAddrType;
+ tDGRAM_SEND_TRACKING *pSentList= NULL;
+ CTELockHandle OldIrq1;
+ ULONG PrevNameTypeState;
+ ULONG LocalNodeType;
+
+ LocalNodeType = AppropriateNodeType( pName, NodeType );
+
+ if ((uAddressType == (USHORT)NBT_UNIQUE ) ||
+ (uAddressType == (USHORT)NBT_QUICK_UNIQUE))
+ {
+ uAddrType = NBT_UNIQUE;
+ }
+ else
+ {
+ uAddrType = NBT_GROUP;
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ if (IpAddress)
+ {
+ status = AddToHashTable(pNbtGlobConfig->pLocalHashTbl,
+ pName,
+ pScope,
+ IpAddress,
+ uAddrType,
+ NULL,
+ &pNameAddr);
+
+ CHECK_PTR(pNameAddr);
+ if (!NT_SUCCESS(status))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(status);
+ }
+ pNameAddr->RefreshMask = 0;
+ }
+ else
+ {
+ // in this case the name is already in the table, we just need
+ // to re-register it
+ //
+ status = FindInHashTable(
+ pNbtGlobConfig->pLocalHashTbl,
+ pName,
+ pScope,
+ &pNameAddr);
+ if (!NT_SUCCESS(status))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(status);
+ }
+ PrevNameTypeState = pNameAddr->NameTypeState;
+ pNameAddr->NameTypeState &= ~NAME_TYPE_MASK;
+ pNameAddr->NameTypeState |= (uAddrType == NBT_UNIQUE) ?
+ NAMETYPE_UNIQUE : NAMETYPE_GROUP;
+
+ if (PrevNameTypeState & NAMETYPE_QUICK)
+ pNameAddr->NameTypeState |= NAMETYPE_QUICK;
+ }
+
+ if ((uAddressType != (USHORT)NBT_UNIQUE ) &&
+ (uAddressType != (USHORT)NBT_QUICK_UNIQUE))
+ {
+ // this means group name so use Bcast Addr - UdpSendDgram changes this
+ // value to the Broadcast address of the particular adapter
+ // when is sees the 0. So when we send to a group name that is
+ // also registered on this node, it will go out as a broadcast
+ // to the subnet as well as to this node.
+ CHECK_PTR(pNameAddr);
+ pNameAddr->IpAddress = 0;
+ }
+
+
+ if (NT_SUCCESS(status))
+ {
+ // set to two minutes until we hear differently from the Name
+ // Server
+ pNameAddr->Ttl = NbtConfig.MinimumTtl;
+
+ // store a ptr to the hash table element in the address element
+ ((tCLIENTELE *)pClientContext)->pAddress->pNameAddr = pNameAddr;
+
+ // for local names, store a back ptr to the address element
+ // in the pAddressEle/pScope field of the nameaddress
+ pNameAddr->pAddressEle = ((tCLIENTELE *)pClientContext)->pAddress;
+
+ //
+ // start with the refreshed bit not set
+ //
+ pNameAddr->RefreshMask &= ~pDeviceContext->AdapterNumber;
+
+ // turn on the adapter's bit in the adapter Mask.
+ //
+ pNameAddr->AdapterMask |= pDeviceContext->AdapterNumber;
+
+ // check for the broadcast netbios name... this name does not
+ // get claimed on the network
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ if (pName[0] == '*')
+ {
+ pNameAddr->NameTypeState |= STATE_RESOLVED;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_SUCCESS);
+ }
+
+ // for "quick" adds, do not register the name on the net!
+ // however the name will get registered with the name server and
+ // refreshed later....if this is an MS or M or P node.
+ //
+ if ((pNameAddr->NameTypeState & NAMETYPE_QUICK) ||
+ (uAddressType >= (USHORT)NBT_QUICK_UNIQUE) )
+ {
+ pNameAddr->NameTypeState |= STATE_RESOLVED;
+ pNameAddr->NameTypeState |= NAMETYPE_QUICK;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_SUCCESS);
+ }
+
+ //
+ // if the address is LoopBack, then there is no ip address for this
+ // adapter and we donot want to attempt a send, since it will just
+ // timeout, so pretend the registration succeeded. Later DHCP will
+ // activate the net card and the names will be registered then.
+ //
+
+ if (IpAddress == LOOP_BACK || pDeviceContext->IpAddress == 0)
+ {
+ pNameAddr->NameTypeState |= STATE_RESOLVED;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(STATUS_SUCCESS);
+ }
+
+ pNameAddr->NameTypeState |= STATE_RESOLVING;
+
+ status = GetTracker(&pSentList);
+ if (!NT_SUCCESS(status))
+ {
+ NbtDereferenceName(pNameAddr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return(status);
+ }
+
+ // there is no list of things sent yet
+ InitializeListHead(&pSentList->Linkage);
+
+ // keep a ptr to the name so we can update the state of the name
+ // later when the registration completes
+
+ pSentList->pNameAddr = pNameAddr;
+ pSentList->pDeviceContext = pDeviceContext;
+
+ // the code must now register the name on the network, depending
+ // on the type of node
+ //
+ Retries = pNbtGlobConfig->uNumBcasts + 1;
+ Timeout = (ULONG)pNbtGlobConfig->uBcastTimeout;
+
+ pCompletionRoutine = MSnodeRegCompletion;
+ pSentList->Flags = NBT_BROADCAST;
+
+ // need to prevent the tracker from being freed by a pdu from
+ // the wire before the UdpSendNsBcast is done
+ //
+ pSentList->RefCount = 2;
+
+ if (LocalNodeType & (PNODE | MSNODE))
+ {
+ // talk to the NS only to register the name
+ // ( the +1 does not actually result in a name reg, it
+ // is just compatible with the code for M node above since
+ // it uses the same completion routine).
+ //
+ Retries = (USHORT)pNbtGlobConfig->uNumRetries + 1;
+ Timeout = (ULONG)pNbtGlobConfig->uRetryTimeout;
+ pSentList->Flags = NBT_NAME_SERVER;
+ //
+ // if there is no Primary WINS server short out the timeout
+ // so it completes faster. For Hnode this means to go broadcast.
+ //
+ if ((pDeviceContext->lNameServerAddress == LOOP_BACK) ||
+ pDeviceContext->WinsIsDown)
+ {
+ if (LocalNodeType & MSNODE)
+ {
+ pSentList->Flags = NBT_BROADCAST;
+ Retries = (USHORT)pNbtGlobConfig->uNumBcasts + 1;
+ Timeout = (ULONG)pNbtGlobConfig->uBcastTimeout;
+
+ IncrementNameStats(NAME_REGISTRATION_SUCCESS,
+ FALSE); // not name server register
+ }
+ else // its a Pnode
+ {
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:WINS DOWN - shorting out registration\n"));
+
+ Retries = 1;
+ Timeout = 10;
+ pSentList->Flags = NBT_NAME_SERVER_BACKUP;
+ }
+ }
+ }
+
+ // the name itself has a reference count too.
+ // make the count 2, so that pNameAddr won't get released until
+ // after DereferenceTracker is called below, since it writes to
+ // pNameAddr. Note that we must increment here rather than set = 2
+ // since it could be a multihomed machine doing the register at
+ // the same time we are sending a datagram to that name.
+ //
+ pNameAddr->RefCount++;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // start the timer in this routine.
+ status = UdpSendNSBcast(
+ pNameAddr,
+ pScope,
+ pSentList,
+ pCompletionRoutine,
+ pClientContext,
+ pClientCompletion,
+ Retries,
+ Timeout,
+ eNAME_REGISTRATION,
+ TRUE);
+
+ // this decrements the reference count and possibly frees the
+ // tracker
+ //
+ DereferenceTracker(pSentList);
+
+ if (NT_SUCCESS(status))
+ {
+ LockedDereferenceName(pNameAddr);
+ return(STATUS_PENDING);
+
+ }
+ else
+ {
+ tTIMERQENTRY *pTimer;
+
+ LOCATION(0x53);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Registration failed - bad retcode from UdpSendNsBcast = %X\n",
+ status));
+
+ // Change the state of the name, so it does not get used
+ // incorrectly. The completion routine will remove the
+ // name from the name table (NbtRegisterCompletion) by
+ // dereferencing the name.
+ //
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= STATE_CONFLICT;
+
+ // free the datagram header since freeing the tracker does not
+ // free the header.
+ if (status != STATUS_INSUFFICIENT_RESOURCES)
+ {
+ CTEMemFree(pSentList->SendBuffer.pDgramHdr);
+ }
+ //
+ // this calls MSNodeRegCompletion which frees the Tracker
+ // back to its queue
+ //
+ pTimer = pNameAddr->pTimer;
+ CHECK_PTR(pNameAddr);
+ pNameAddr->pTimer = NULL;
+
+ NbtDereferenceName(pNameAddr);
+
+ DereferenceTrackerNoLock(pSentList);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ }
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+MSnodeRegCompletion(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the timer code when the timer expires. It must
+ decide if another name registration should be done, and if not, then it calls the
+ client's completion routine (in completion2).
+ It first attempts to register a name via Broadcast, then it attempts
+ NameServer name registration.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ USHORT Flags;
+ CTELockHandle OldIrq;
+ enum eNSTYPE PduType;
+ ULONG LocalNodeType;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+ PduType = eNAME_REGISTRATION;
+
+ LocalNodeType = AppropriateNodeType( pTracker->pNameAddr->Name, NodeType );
+
+ //
+ // check if the client completion routine is still set. If not then the
+ // timer has been cancelled and this routine should just clean up its
+ // buffers associated with the tracker.
+ //
+ if (pTimerQEntry)
+ {
+ //
+ // to prevent a client from stopping the timer and deleting the
+ // pNameAddr, grab the lock and check if the timer has been stopped
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (pTimerQEntry->Flags & TIMER_RETIMED)
+ {
+ pTimerQEntry->Flags &= ~TIMER_RETIMED;
+ pTimerQEntry->Flags |= TIMER_RESTART;
+
+ if ((!pTracker->pDeviceContext->pNameServerFileObject) ||
+ (pTracker->Flags & NBT_NAME_SERVER) &&
+ (pTracker->pDeviceContext->lNameServerAddress == LOOP_BACK))
+ {
+ // when the address is loop back there is no wins server
+ // so shorten the timeout.
+ //
+ pTimerQEntry->DeltaTime = 10;
+ }
+ else
+ if ((pTracker->Flags & NBT_NAME_SERVER_BACKUP) &&
+ (pTracker->pDeviceContext->lBackupServer == LOOP_BACK))
+ {
+ // when the address is loop back there is no wins server
+ // so shorten the timeout.
+ //
+ pTimerQEntry->DeltaTime = 10;
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return;
+ }
+ if (pTimerQEntry->ClientCompletion)
+ {
+ // if number of retries is not zero then continue trying to contact the
+ // Name Server
+ //
+ if (--pTimerQEntry->Retries)
+ {
+
+ // change the name reg pdu to a name overwrite request for the
+ // final broadcast ( turn off Recursion Desired bit)
+ //
+ if (pTimerQEntry->Retries == 1)
+ {
+ if (pTracker->Flags & NBT_BROADCAST)
+ {
+ // do a broadcast name registration... on the last broadcast convert it to
+ // a Name OverWrite Request by clearing the "Recursion Desired" bit
+ // in the header
+ //
+ PduType = eNAME_REGISTRATION_OVERWRITE;
+ }
+ else
+ if (LocalNodeType & (PNODE | MSNODE))
+ {
+ // we want the Pnode to timeout again, right away and fall
+ // through to handle Timed out name registration - i.e. it
+ // does not do the name overwrite demand like the B,M,&MS nodes
+ //
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ pTimerQEntry->DeltaTime = 5;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return;
+
+ }
+ }
+ }
+ else
+ {
+ Flags = pTracker->Flags;
+ pTracker->Flags &= ~(NBT_BROADCAST | NBT_NAME_SERVER);
+ // set a different timeout for nameserver name registration
+ //
+ pTimerQEntry->DeltaTime = NbtConfig.uRetryTimeout;
+ pTimerQEntry->Retries = NbtConfig.uNumRetries + 1;
+
+ if ((Flags & NBT_BROADCAST) && (LocalNodeType & MNODE))
+ {
+ //
+ // Registered through broadcast, so try the name server now.
+ IncrementNameStats(NAME_REGISTRATION_SUCCESS,
+ FALSE); // not name server register
+
+ //
+ pTracker->Flags |= NBT_NAME_SERVER;
+ if ((pTracker->pDeviceContext->lNameServerAddress == LOOP_BACK) ||
+ pTracker->pDeviceContext->WinsIsDown)
+ {
+ pTimerQEntry->DeltaTime = 10;
+ pTimerQEntry->Retries = 1;
+
+ }
+ }
+ else
+ if ((Flags & NBT_NAME_SERVER) && !(LocalNodeType & BNODE))
+ {
+ //
+ // Can't reach the name server, so try the backup
+
+ pTracker->Flags |= NBT_NAME_SERVER_BACKUP;
+ //
+ // short out the timer if no backup server
+ //
+ if ((pTracker->pDeviceContext->lBackupServer == LOOP_BACK) ||
+ pTracker->pDeviceContext->WinsIsDown)
+ {
+ pTimerQEntry->DeltaTime = 10;
+ pTimerQEntry->Retries = 1;
+
+ }
+ }
+ else
+ if ((LocalNodeType & MSNODE) && !(Flags & NBT_BROADCAST))
+ {
+ if (Flags & NBT_NAME_SERVER_BACKUP)
+ {
+ // the msnode switches to broadcast if all else fails
+ //
+ pTracker->Flags |= NBT_BROADCAST;
+ IncrementNameStats(NAME_REGISTRATION_SUCCESS,
+ FALSE); // not name server register
+
+ //
+ // change the timeout and retries since
+ // broadcast uses a shorter timeout
+ //
+ pTimerQEntry->DeltaTime = NbtConfig.uBcastTimeout;
+ pTimerQEntry->Retries = (USHORT)pNbtGlobConfig->uNumBcasts + 1;
+ }
+ }
+ else
+ {
+
+ if (LocalNodeType & BNODE)
+ {
+ IncrementNameStats(NAME_REGISTRATION_SUCCESS,
+ FALSE); // not name server register
+ }
+ //
+ // the timeout has expired on the name registration
+ // so call the client
+ //
+
+ // return the tracker block to its queue
+ LOCATION(0x54);
+
+ //
+ // start a timer to stop using WINS for a short period of
+ // time.
+ //
+ SetWinsDownFlag(pTracker->pDeviceContext);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ DereferenceTracker(pTracker);
+ status = STATUS_SUCCESS;
+ InterlockedCallCompletion(pTimerQEntry,status);
+
+ return;
+ }
+ }
+ pTracker->RefCount++;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = UdpSendNSBcast(pTracker->pNameAddr,
+ NbtConfig.pScope,
+ pTracker,
+ NULL,NULL,NULL,
+ 0,0,
+ PduType,
+ TRUE);
+
+ DereferenceTracker(pTracker);
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ }
+ else
+ {
+ // return the tracker block to its queue
+ LOCATION(0x55);
+ DereferenceTrackerNoLock(pTracker);
+ }
+
+
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+NodeStatusCompletion(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the NodeStatus timeouts on packets sent to nodes
+ that do not respond in a timely manner to node status. This routine will
+ resend the request.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID pClientContext;
+ PCHAR pName0;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ if (pTimerQEntry)
+ {
+
+
+ if (--pTimerQEntry->Retries)
+ {
+ PUCHAR pHdr;
+ ULONG Length;
+ ULONG UNALIGNED * pAddress;
+ PFILE_OBJECT pFileObject;
+
+ // send the Datagram...increment ref count
+ pTracker->RefCount++;
+
+ //
+ // the node status is almost identical with the query pdu so use it
+ // as a basis and adjust it . We always rebuild the Node status
+ // request since the datagram gets freed when the irp is returned
+ // from the transport in NsDgramSendCompleted.
+ //
+
+ pName0 = Nbt_inet_addr(pTracker->pNameAddr->Name)
+ ? "*\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" : pTracker->pNameAddr->Name;
+ pAddress = (ULONG UNALIGNED *)CreatePdu(pName0,
+ NbtConfig.pScope,
+ 0L,
+ 0,
+ eNAME_QUERY,
+ (PVOID)&pHdr,
+ &Length,
+ pTracker);
+ if (pAddress)
+ {
+ // clear the recursion desired bit
+ //
+ ((PUSHORT)pHdr)[1] &= ~FL_RECURDESIRE;
+
+ // set the NBSTAT field to 21 rather than 20
+ pHdr[Length-3] = (UCHAR)QUEST_STATUS;
+
+
+ // fill in the tracker data block
+ // note that the passed in transport address must stay valid till this
+ // send completes
+ pTracker->SendBuffer.pDgramHdr = (PVOID)pHdr;
+ if (pTracker->pDeviceContext->IpAddress)
+ {
+ pFileObject = pTracker->pDeviceContext->pNameServerFileObject;
+ }
+ else
+ pFileObject = NULL;
+ status = UdpSendDatagram(
+ pTracker,
+ pTracker->pNameAddr->IpAddress,
+ pFileObject,
+ NameDgramSendCompleted,
+ pHdr,
+ NBT_NAMESERVICE_UDP_PORT,
+ NBT_NAME_SERVICE);
+
+ }
+
+ DereferenceTracker(pTracker);
+
+ // always restart even if the above send fails, since it might succeed
+ // later.
+ pTimerQEntry->Flags |= TIMER_RESTART;
+
+ }
+ else
+ {
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ pClientCompletion = pTimerQEntry->ClientCompletion;
+ pClientContext = pTimerQEntry->ClientContext;
+ CHECK_PTR(pTimerQEntry);
+ pTimerQEntry->ClientCompletion = NULL;
+
+
+ // if the client routine has not yet run, run it now.
+ if (pClientCompletion)
+ {
+
+ // unlink the tracker from the node status Q if we successfully
+ // called the completion routine. Note, remove from the
+ // list before calling the completion routine to coordinate
+ // with DecodeNodeStatusResponse in inbound.c
+ //
+ RemoveEntryList(&pTracker->Linkage);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // Do not dereference here since Node Status Done will do
+ // the dereference
+ //
+ // DereferenceTracker(pTracker);
+
+ //
+ // pClientContext will be zero if we came here through nbtstat
+ //
+ if (!pClientContext)
+ pClientContext = pTracker;
+
+ (*pClientCompletion)(
+ pClientContext,
+ STATUS_TIMEOUT);
+ return;
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return;
+ }
+ }
+ else
+ {
+ //
+ // Do not dereference here since Node Status Done will do
+ // the dereference
+ //
+ //DereferenceTrackerNoLock(pTracker);;
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+RefreshRegCompletion(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the name Refresh timeouts on packets sent to the Name
+ Service. I.e it sends refreshes to the nameserver until a response is
+ heard or the number of retries is exceeded.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tNAMEADDR *pNameAddr;
+ CTELockHandle OldIrq;
+ COMPLETIONCLIENT pCompletionClient;
+
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ if (pTimerQEntry)
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // check if the timer has been stopped yet, since stopping the timer
+ // nulls the client completion routine. If not null, increment the
+ // tracker refcount, so that the last refresh completing cannot
+ // free the tracker out from under us.
+ //
+ pCompletionClient = pTimerQEntry->ClientCompletion;
+ if (pCompletionClient)
+ {
+ // if still some count left and not refreshed yet
+ // then do another refresh request
+ //
+ pNameAddr = pTracker->pNameAddr;
+
+ if (--pTimerQEntry->Retries)
+ {
+ pTracker->RefCount++;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = UdpSendNSBcast(pTracker->pNameAddr,
+ NbtConfig.pScope,
+ pTracker,
+ NULL,NULL,NULL,
+ 0,0,
+ eNAME_REFRESH,
+ TRUE);
+
+ // always restart even if the above send fails, since it might succeed
+ // later.
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ DereferenceTracker(pTracker);
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ // this calls the completion routine synchronizing with the
+ // timer expiry code.
+ InterlockedCallCompletion(pTimerQEntry,STATUS_TIMEOUT);
+ }
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ ULONG
+SetFirstDeviceContext(
+ OUT tDEVICECONTEXT **ppDeviceContext,
+ IN tNAMEADDR *pNameAddr
+ )
+/*++
+
+Routine Description:
+
+ This routine finds the first adapter as specified in the name's adapter
+ mask and set the DeviceContext associated with it. It then clears the
+ bit in the adapter mask of pNameAddr.
+
+Arguments:
+
+
+Return Value:
+
+ TRUE if pNameAddr->AdapterMask != 0
+
+--*/
+{
+ CTEULONGLONG AdapterNumber = 1;
+ CTEULONGLONG i;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ while (!(AdapterNumber & pNameAddr->AdapterMask))
+ {
+ AdapterNumber = AdapterNumber <<1;
+ }
+
+ pHead = &NbtConfig.DeviceContexts;
+ pEntry = pHead->Flink;
+ for (i=1;i < AdapterNumber ;i = i << 1 )
+ {
+ pEntry = pEntry->Flink;
+ }
+
+ *ppDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+
+ // turn off the adapter bit since we are releasing the name on this adapter
+ // now.
+ //
+ pNameAddr->AdapterMask &= ~AdapterNumber;
+
+ return TRUE;
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+ReleaseNameOnNet(
+ tNAMEADDR *pNameAddr,
+ PCHAR pScope,
+ PVOID pClientContext,
+ PVOID pClientCompletion,
+ ULONG LocalNodeType,
+ tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine deletes a name on the network either by a
+ broadcast or by talking to the NS depending on the type of node. (M,P or B)
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+Called By: ProxyQueryFromNet() in proxy.c, NbtConnect() in name.c
+
+--*/
+
+{
+ ULONG Timeout;
+ USHORT Retries;
+ NTSTATUS status=STATUS_UNSUCCESSFUL;
+ tDGRAM_SEND_TRACKING *pTracker;
+ USHORT uAddrType;
+ CTELockHandle OldIrq;
+ tDEVICECONTEXT *pReleaseDeviceContext;
+
+ // ASSERT(pNameAddr->AdapterMask); // This fails when NbtDestroyDeviceObject
+ // is called and the name has already been released
+
+ //
+ // If this name is not registered on any adapters, return STATUS_UNSUCCESSFUL
+ //
+ if (pNameAddr->AdapterMask == 0)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // Find the DeviceContext specified by the Adapter mask in pNameAddr
+ // and clear the corresponding bit in pNameAddr->AdapterMask
+ // Return FALSE if no Adapter was specified
+ //
+ if (pDeviceContext)
+ {
+ pReleaseDeviceContext = pDeviceContext;
+ pNameAddr->AdapterMask &= ~(pDeviceContext->AdapterNumber);
+ }
+ else if (!SetFirstDeviceContext(&pReleaseDeviceContext,pNameAddr))
+ {
+ return (status);
+ }
+
+ status = GetTracker(&pTracker);
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+ CHECK_PTR(pTracker);
+
+ pTracker->pDeviceContext = pReleaseDeviceContext;
+ LocalNodeType = AppropriateNodeType( pNameAddr->Name, LocalNodeType );
+
+ // set to NULL to catch any erroneous frees.
+ pTracker->SendBuffer.pDgramHdr = NULL;
+
+ // Set a few values as a precursor to releasing the name either by
+ // broadcast or with the name server
+ //
+ switch (LocalNodeType & NODE_MASK)
+ {
+ case MSNODE:
+ case MNODE:
+ case PNODE:
+
+ Retries = (USHORT)pNbtGlobConfig->uNumRetries;
+ Timeout = (ULONG)pNbtGlobConfig->uRetryTimeout;
+
+ pTracker->Flags = NBT_NAME_SERVER;
+ break;
+
+ case BNODE:
+ default:
+
+#ifndef VXD
+ Retries = (USHORT)pNbtGlobConfig->uNumBcasts;
+#else
+ Retries = (USHORT)1;
+#endif
+ Timeout = (ULONG)pNbtGlobConfig->uBcastTimeout;
+ pTracker->Flags = NBT_BROADCAST;
+ }
+ //
+ // Release name on the network
+ //
+ if ((pNameAddr->NameTypeState & NAME_TYPE_MASK) != NAMETYPE_UNIQUE)
+ {
+ uAddrType = NBT_GROUP;
+ }
+ else
+ {
+ uAddrType = NBT_UNIQUE;
+ }
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Doing Name Release on name %16.16s<%X>\n",
+ pNameAddr->Name,pNameAddr->Name[15]));
+
+ pTracker->RefCount = 2;
+ status = UdpSendNSBcast(pNameAddr,
+ pScope,
+ pTracker,
+ ReleaseCompletion,
+ pClientContext,
+ pClientCompletion,
+ Retries,
+ Timeout,
+ eNAME_RELEASE,
+ TRUE);
+
+ DereferenceTracker(pTracker);
+
+ if (!NT_SUCCESS(status))
+ {
+ NTSTATUS Locstatus;
+ COMPLETIONCLIENT pCompletion;
+ PVOID pContext;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Query failed - bad retcode from UdpSendNsBcast during name release= %X\n",
+ status));
+
+ // Stopping the timer will call ReleaseCompletion which will
+ // free the tracker
+ //
+ pCompletion = NULL;
+ if (pNameAddr->pTimer)
+ {
+ Locstatus = StopTimer(pNameAddr->pTimer,&pCompletion,&pContext);
+
+ CHECK_PTR(pNameAddr);
+ pNameAddr->pTimer = NULL;
+ }
+ else
+ {
+ // no timer setup, so just free the tracker - but check if we
+ // have a hdr to free too.
+ //
+ if (status != STATUS_INSUFFICIENT_RESOURCES)
+ {
+ FreeTracker(pTracker, FREE_HDR | RELINK_TRACKER);
+ }
+ else
+ {
+ FreeTracker(pTracker, RELINK_TRACKER);
+ }
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ return(status);
+}
+//----------------------------------------------------------------------------
+ VOID
+ReleaseCompletion(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the timer code when the timer expires. It must
+ decide if another name query should be done, and if not, then it calls the
+ client's completion routine (in completion2).
+ This routine handles both the broadcast portion of the name queries and
+ the WINS server directed sends.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ ULONG LocalNodeType;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ if (IsBrowserName(pTracker->pNameAddr->Name))
+ {
+ LocalNodeType = BNODE;
+ }
+ else
+ {
+ LocalNodeType = NodeType;
+ }
+
+ //
+ // check if the client completion routine is still set. If not then the
+ // timer has been cancelled and this routine should just clean up its
+ // buffers associated with the tracker.
+ //
+ if (pTimerQEntry)
+ {
+ // if number of retries is not zero then continue trying to contact the
+ // Name Server.
+ //
+ if (!(--pTimerQEntry->Retries))
+ {
+ if ((LocalNodeType & MNODE) &&
+ (pTracker->Flags & NBT_NAME_SERVER))
+ {
+ //
+ // try broadcast
+ //
+ pTracker->Flags &= ~NBT_NAME_SERVER;
+ pTracker->Flags |= NBT_BROADCAST;
+
+ // set a different timeout for broadcast name resolution
+ //
+ pTimerQEntry->DeltaTime = NbtConfig.uBcastTimeout;
+ pTimerQEntry->Retries = NbtConfig.uNumBcasts;
+
+
+ }
+ else
+ {
+ //
+ // the timeout has expired on the name release
+ // so call the client
+ //
+ status = InterlockedCallCompletion(pTimerQEntry,STATUS_TIMEOUT);
+
+ // return the tracker block to its queue if we successfully
+ // called the completion routine since someone else might
+ // have done a Stop timer at this very moment and freed the
+ // tracker already (i.e. the last else clause in this routine).
+ //
+ if (NT_SUCCESS(status))
+ {
+ DereferenceTracker(pTracker);;
+ }
+ return;
+
+ }
+
+ }
+
+ pTracker->RefCount++;
+ status = UdpSendNSBcast(pTracker->pNameAddr,
+ NbtConfig.pScope,
+ pTracker,
+ NULL,NULL,NULL,
+ 0,0,
+ eNAME_RELEASE,
+ TRUE);
+
+ DereferenceTracker(pTracker);
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ }
+ else
+ {
+ // return the tracker block to its queue
+ DereferenceTrackerNoLock(pTracker);;
+ }
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NameReleaseDoneOnDynIf(
+ PVOID pContext,
+ NTSTATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a name is released on the network for a deleted dynamic If.
+ Itsmain, role in life is to free the memory in Context, which is the pAddressEle
+ structure.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+Called By Release Completion (above)
+--*/
+
+{
+ CTELockHandle OldIrq1;
+ tADDRESSELE *pAddress;
+ tNAMEADDR *pNameAddr;
+
+ pAddress = (tADDRESSELE *)pContext;
+ pNameAddr = pAddress->pNameAddr;
+
+
+ //
+ // If last device, release resources.
+ //
+ if (!pNameAddr->AdapterMask)
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ // this should remove and delete the name from the local table. Since it
+ // is possible to re-register the name during the name release on the
+ // net, we need this check here for the ref count, since NbtOpenAddress
+ // will increment it if is going to reregister it.
+ //
+ if (pAddress->RefCount == 0)
+ {
+
+ // remove the address object from the list of addresses tied to the
+ // device context for the adapter
+ //
+ RemoveEntryList(&pAddress->Linkage);
+
+ CHECK_PTR(pAddress->pNameAddr);
+ pAddress->pNameAddr->pAddressEle = NULL;
+
+ ASSERT(IsListEmpty(&pAddress->ClientHead));
+
+ // check if pnameaddr memory already freed
+ ASSERT(pAddress->pNameAddr->pAddressEle != (PVOID)0xD1000000);
+
+ NbtDereferenceName(pAddress->pNameAddr);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // free the memory associated with the address element
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("NBt: Deleteing Address Obj after name release on net %X\n",pAddress));
+ NbtFreeAddressObj(pAddress);
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ }
+ }
+
+}
+//----------------------------------------------------------------------------
+ VOID
+NameReleaseDone(
+ PVOID pContext,
+ NTSTATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a name is released on the network. Its
+ main, role in life is to free the memory in Context, which is the pAddressEle
+ structure.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+Called By Release Completion (above)
+--*/
+
+{
+ CTELockHandle OldIrq1;
+ tADDRESSELE *pAddress;
+ tNAMEADDR *pNameAddr;
+
+ pAddress = (tADDRESSELE *)pContext;
+ pNameAddr = pAddress->pNameAddr;
+
+
+ if (pNameAddr->AdapterMask)
+ {
+ // the name is not released for all adapters yet
+ //
+ ReleaseNameOnNet(pNameAddr,
+ NbtConfig.pScope,
+ pAddress,
+ NameReleaseDone,
+ NodeType,
+ NULL);
+ }
+ else
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ // this should remove and delete the name from the local table. Since it
+ // is possible to re-register the name during the name release on the
+ // net, we need this check here for the ref count, since NbtOpenAddress
+ // will increment it if is going to reregister it.
+ //
+ if (pAddress->RefCount == 0)
+ {
+
+ // remove the address object from the list of addresses tied to the
+ // device context for the adapter
+ //
+ RemoveEntryList(&pAddress->Linkage);
+
+ CHECK_PTR(pAddress->pNameAddr);
+ pAddress->pNameAddr->pAddressEle = NULL;
+
+ ASSERT(IsListEmpty(&pAddress->ClientHead));
+
+ // check if pnameaddr memory already freed
+ ASSERT(pAddress->pNameAddr->pAddressEle != (PVOID)0xD1000000);
+
+ NbtDereferenceName(pAddress->pNameAddr);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // free the memory associated with the address element
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("NBt: Deleteing Address Obj after name release on net %X\n",pAddress));
+ NbtFreeAddressObj(pAddress);
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ }
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+DereferenceTracker(
+ IN tDGRAM_SEND_TRACKING *pTracker
+ )
+/*++
+
+Routine Description:
+
+ This routine cleans up a Tracker block and puts it back on the free
+ queue. The JointLock Spin lock should be held before calling this
+ routine to coordinate access to the tracker ref count.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (--pTracker->RefCount)
+ {
+ LOCATION(0x56);
+ }
+ else
+ {
+ LOCATION(0x99);
+
+ // the datagram header may have already been freed
+ //
+ FreeTracker(pTracker, RELINK_TRACKER);
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+}
+//----------------------------------------------------------------------------
+ VOID
+DereferenceTrackerNoLock(
+ IN tDGRAM_SEND_TRACKING *pTracker
+ )
+/*++
+
+Routine Description:
+
+ This routine cleans up a Tracker block and puts it back on the free
+ queue. The JointLock Spin lock should be held before calling this
+ routine to coordinate access to the tracker ref count.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ if (--pTracker->RefCount)
+ {
+ LOCATION(0x56);
+ }
+ else
+ {
+ LOCATION(0x99);
+
+ // the datagram header may have already been freed
+ //
+ FreeTracker(pTracker, RELINK_TRACKER);
+ }
+}
+//----------------------------------------------------------------------------
+ VOID
+DereferenceTrackerDelete(
+ IN tDGRAM_SEND_TRACKING *pTracker
+ )
+/*++
+
+Routine Description:
+
+ This routine frees the datagram hdr and puts the Tracker block back on the free
+ queue.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (--pTracker->RefCount)
+ {
+ LOCATION(0xA9);
+ return;
+ }
+ else
+ {
+ LOCATION(0xAA);
+
+ // the datagram header may have already been freed
+ //
+ FreeTracker(pTracker, FREE_HDR | RELINK_TRACKER);
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+StartRefresh(
+ IN tNAMEADDR *pNameAddr,
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN BOOLEAN ResetDevice
+ )
+/*++
+
+Routine Description:
+
+ This routine handles refreshing a name with the Name server.
+
+ The idea is to set the timeout to T/8 and check for names with the Refresh
+ bit cleared - re-registering those names. At T=4 and T=0, clear all bits
+ and refresh all names. The Inbound code sets the refresh bit when it gets a
+ refresh response from the NS.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ CTELockHandle OldIrq;
+ NTSTATUS status;
+ tDEVICECONTEXT *pDeviceContext;
+ BOOLEAN NewTracker;
+
+ if (!pTracker)
+ {
+ LOCATION(0x9);
+ status = GetTracker(&pTracker);
+ if (!NT_SUCCESS(status))
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pTracker->Flags = NBT_NAME_SERVER;
+
+ NewTracker = TRUE;
+
+ // need to prevent the tracker from being freed by a pdu from
+ // the wire before the UdpSendNsBcast is done
+ //
+ pTracker->RefCount = 2;
+ }
+ else
+ {
+ NewTracker = FALSE;
+ LOCATION(0xa);
+ // this accounts for the dereference done after the call to
+ // send the datagram below.
+ pTracker->RefCount += 1;
+ }
+
+
+ // set the name to be refreshed in the tracker block
+ pTracker->pNameAddr = pNameAddr;
+
+ // this is set true when a new name gets refreshed
+ //
+ if (ResetDevice)
+ {
+ PLIST_ENTRY pEntry;
+ CTEULONGLONG AdapterMask;
+ CTEULONGLONG AdapterNumber = 1;
+ ULONG i;
+
+ LOCATION(0xb);
+
+ //
+ // Travel to the actual device this name is registered on
+ //
+ pEntry = NbtConfig.DeviceContexts.Flink;
+ AdapterMask = pNameAddr->AdapterMask;
+
+ if (AdapterMask) {
+ while (!(AdapterNumber & AdapterMask))
+ {
+ AdapterNumber = AdapterNumber << 1;
+ }
+
+ for (i = 1;i < AdapterNumber ;i = i << 1 ) {
+ pEntry = pEntry->Flink;
+ }
+ }
+
+ pDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+
+ IF_DBG(NBT_DEBUG_REFRESH)
+ KdPrint(("Nbt: Refresh adapter: %lx:%lx, dev.nm: %lx for name: %lx\n",
+ AdapterNumber, pDeviceContext->BindName.Buffer, pNameAddr));
+
+ pTracker->pDeviceContext = pDeviceContext;
+ //
+ // Clear the transaction Id so that CreatePdu will increment
+ // it for this new name
+ //
+ CHECK_PTR(pTracker);
+ pTracker->TransactionId = 0;
+ }
+
+ status = UdpSendNSBcast(
+ pNameAddr,
+ NbtConfig.pScope,
+ pTracker,
+ RefreshRegCompletion,
+ pTracker,
+ NextRefresh,
+ NbtConfig.uNumRetries,
+ NbtConfig.uRetryTimeout,
+ eNAME_REFRESH,
+ TRUE);
+
+ DereferenceTracker(pTracker);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ LOCATION(0x57);
+
+ if (!NT_SUCCESS(status))
+ {
+
+ LOCATION(0xe);
+
+
+ //
+ // This will free the tracker. Name refresh will stop until
+ // the next refresh timeout and at that point it will attempt
+ // to refresh the names again.
+ //
+ DereferenceTrackerNoLock(pTracker);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ IF_DBG(NBT_DEBUG_REFRESH)
+ KdPrint(("Nbt:Failed to send Refresh!! status = %X****\n",status));
+ return(status);
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+GetNextName(
+ IN tNAMEADDR *pNameAddrIn,
+ OUT tNAMEADDR **ppNameAddr
+ )
+/*++
+
+Routine Description:
+
+ This routine finds the next name to refresh, including incrementing the
+ reference count so that the name cannot be deleted during the refresh.
+ The JointLock spin lock is held before calling this routine.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ LONG i;
+ tNAMEADDR *pNameAddr;
+ tHASHTABLE *pHashTable;
+
+
+ pHashTable = NbtConfig.pLocalHashTbl;
+
+ for (i= NbtConfig.CurrentHashBucket;i < pHashTable->lNumBuckets ;i++ )
+ {
+ //
+ // use the last name as the current position in the linked list
+ // only if that name is still resolved, otherwise start at the
+ // begining of the hash list, incase the name got deleted in the
+ // mean time.
+ //
+ if (pNameAddrIn && (pNameAddrIn->NameTypeState & STATE_RESOLVED))
+ {
+ pHead = &NbtConfig.pLocalHashTbl->Bucket[NbtConfig.CurrentHashBucket];
+ pEntry = pNameAddrIn->Linkage.Flink;
+
+ pNameAddrIn = NULL;
+ }
+ else
+ {
+ pHead = &pHashTable->Bucket[i];
+ pEntry = pHead->Flink;
+ }
+
+ while (pEntry != pHead)
+ {
+ CTEULONGLONG AllRefreshed;
+
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+
+ // don't refresh scope names or names in conflict or that are the
+ // broadcast name "* " or quick unique names - i.e. the permanent
+ // name is nametype quick
+ //
+ if (!(pNameAddr->NameTypeState & STATE_RESOLVED) ||
+ (pNameAddr->Name[0] == '*') ||
+ (pNameAddr->NameTypeState & NAMETYPE_QUICK))
+ {
+ pEntry = pEntry->Flink;
+ continue;
+ }
+
+ // check if the name has been refreshed yet
+ // build a value with ones set for all adapter numbers by shifting
+ // 1 one bit position further and then subtracting 1.
+ // i.e. 100 -1 = 11 (binary) or 4-3 = 3(11 binary)
+ //
+ AllRefreshed = ((CTEULONGLONG)1 << NbtConfig.AdapterCount) -1;
+ if (pNameAddr->RefreshMask == AllRefreshed)
+ {
+ pEntry = pEntry->Flink;
+ continue;
+ }
+
+ // increment the reference count so that this name cannot
+ // disappear while it is being refreshed and screw up the linked
+ // list
+ CTEInterlockedIncrementLong(&pNameAddr->pAddressEle->RefCount);
+
+ NbtConfig.CurrentHashBucket = (USHORT)i;
+
+ *ppNameAddr = pNameAddr;
+ return;
+ }
+ }
+
+ *ppNameAddr = NULL;
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+NextRefresh(
+ IN PVOID pContext,
+ IN NTSTATUS CompletionStatus
+ )
+/*++
+
+Routine Description:
+
+ This routine queues the work to an Executive worker thread to handle
+ refreshing the next name.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ LOCATION(0xf);
+ CTEQueueForNonDispProcessing(pTracker,(PVOID)CompletionStatus,NULL,
+ NextRefreshNonDispatch,pTracker->pDeviceContext);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NextRefreshNonDispatch(
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles sending subsequent refreshes to the name server.
+ This is the "Client Completion" routine of the Timer started above.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ CTELockHandle OldIrq;
+ tNAMEADDR *pNameAddr;
+ tNAMEADDR *pNameAddrNext;
+ NTSTATUS status;
+ PLIST_ENTRY pEntry;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tDEVICECONTEXT *pDeviceContext;
+ CTEULONGLONG AdapterNumber;
+ CTEULONGLONG AdapterMask;
+ CTEULONGLONG i;
+ BOOLEAN AbleToReachWins = FALSE;
+ NTSTATUS CompletionStatus;
+
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)pContext)->pTracker;
+ CompletionStatus = (NTSTATUS)((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
+
+ pNameAddr = pTracker->pNameAddr;
+ ASSERT(pNameAddr);
+
+ //
+ // grab the resource so that a name refresh response cannot start running this
+ // code in a different thread before this thread has exited this routine,
+ // otherwise the tracker can get dereferenced twice and blown away.
+ //
+ CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ LOCATION(0x1);
+ // turn on the bit corresponding to this adapter, since the name refresh
+ // completed ok
+ //
+ if (CompletionStatus == STATUS_SUCCESS)
+ {
+ LOCATION(0x2);
+ pNameAddr->RefreshMask |= pTracker->pDeviceContext->AdapterNumber;
+ AbleToReachWins = TRUE;
+ }
+ else
+ if (CompletionStatus != STATUS_TIMEOUT)
+ {
+ LOCATION(0x3);
+ // if the timer times out and we did not get to the name server, then
+ // that is not an error. However, any other bad status
+ // must be a negative response to a name refresh so mark the name
+ // in conflict
+ //
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= STATE_CONFLICT;
+ AbleToReachWins = TRUE;
+ }
+
+ // for the multihomed case a failure to reach wins out one of the adapters
+ // is not necessarily a failure to reach any WINS. Since this flag
+ // is just an optimization to prevent clients from continually trying to
+ // register all of their names if WINS is unreachable, we can ignore the
+ // optimization for the multihomed case. The few nodes that are
+ // multihomed will not create that much traffic compared to possibly
+ // thousands that are singly homed clients.
+ if (NbtConfig.MultiHomed)
+ {
+ AbleToReachWins = TRUE;
+ }
+ //
+ // get the next name in the hash table only if we have refreshed
+ // all adapters for this name i.e.
+ // check if any higher bits are set inthe AdapterMask
+ //
+ AdapterNumber = pTracker->pDeviceContext->AdapterNumber;
+
+ // go to the next adapter
+ AdapterNumber = AdapterNumber << 1;
+
+ //
+ // still more adapters to check ...
+ //
+ if (pNameAddr->AdapterMask >= AdapterNumber)
+ {
+ BOOLEAN Found;
+
+ // go to the next device context and refresh the name there
+ // using the same tracker.
+ //
+ LOCATION(0x8);
+
+ //
+ // look for a device context with a valid IP address since there is
+ // no sense in refreshing names out unconnected RAS links.
+ //
+ Found = FALSE;
+ while (!Found)
+ {
+ AdapterMask = pNameAddr->AdapterMask;
+ while (!(AdapterNumber & AdapterMask))
+ {
+ AdapterNumber = AdapterNumber << 1;
+ }
+
+ IF_DBG(NBT_DEBUG_REFRESH)
+ KdPrint(("Nbt:Refresh on Adapter %X, Name %15.15s<%X>\n",
+ (ULONG)AdapterNumber,pNameAddr->Name,pNameAddr->Name[15]));
+
+ // get the nth devicecontext in the list
+ //
+ pEntry = NbtConfig.DeviceContexts.Flink;
+ for (i = 1;i < AdapterNumber ;i = i << 1 )
+ {
+ pEntry = pEntry->Flink;
+ }
+
+ pDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+
+ //
+ // find an adapter with a valid ip address and name server address
+ //
+ if ((pDeviceContext->IpAddress != LOOP_BACK) &&
+ (pDeviceContext->lNameServerAddress != LOOP_BACK))
+ {
+
+ pTracker->pDeviceContext = pDeviceContext;
+
+ // remove the previous timer from the addressele since StartRefresh
+ // will start a new timer - safety measure and probably not required!
+ //
+ CHECK_PTR(pNameAddr);
+ pNameAddr->pTimer = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // this call sends out a name registration PDU on a different adapter
+ // to (potentially) a different name server. The Name service PDU
+ // is the same as the last one though...no need to create a new one.
+ //
+ status = StartRefresh(pNameAddr,pTracker,FALSE);
+ if (!NT_SUCCESS(status))
+ {
+ DereferenceTracker(pTracker);
+ NbtConfig.DoingRefreshNow = FALSE;
+ }
+ goto ExitRoutine;
+ }
+
+ // go to the next adapter
+ AdapterNumber = AdapterNumber << 1;
+
+
+ if (pNameAddr->AdapterMask < AdapterNumber)
+ {
+ // no more adapters so try the next name below...
+ break;
+ }
+ }
+ }
+
+
+ if (pNameAddr->AdapterMask < AdapterNumber)
+ {
+ // the name's adapter mask does not go this high in adapters, so go on
+ // to the next name.
+ //
+
+ // if we failed to reach WINS on the last refresh, stop refreshing
+ // until the next time interval. This cuts down on network traffic.
+ //
+ LOCATION(0x4);
+ if (AbleToReachWins)
+ {
+ LOCATION(0x5);
+ GetNextName(pNameAddr,&pNameAddrNext);
+ }
+ else
+ pNameAddrNext = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ if (pNameAddrNext)
+ {
+ // reset back to the first adapter for this new name
+ //
+ LOCATION(0x6);
+ status = StartRefresh(pNameAddrNext,pTracker,TRUE);
+ if (!NT_SUCCESS(status))
+ {
+ NbtConfig.DoingRefreshNow = FALSE;
+ DereferenceTracker(pTracker);
+ KdPrint(("Nbt:StartRefresh failed on Adapter %X, Name %15.15s<%x>, status=%X\n",
+ (ULONG)AdapterNumber,pNameAddr->Name,pNameAddr->Name[15], status));
+ }
+ IF_DBG(NBT_DEBUG_REFRESH)
+ KdPrint(("Nbt:Refresh on Adapter %X, Name %15.15s<%x>\n",
+ (ULONG)AdapterNumber,pNameAddr->Name,pNameAddr->Name[15]));
+ }
+
+ // *** this code cleans up the previously refreshed name ***
+
+ // clear the timer entry ptr in the address record so the dereference
+ // can proceed to completion. NOTE: the caller of this routine must
+ // NOT reference pAddressEle since the memory may have been freed here
+ //
+ CHECK_PTR(pNameAddr);
+ pNameAddr->pTimer = NULL;
+
+ NbtDereferenceAddress(pNameAddr->pAddressEle);
+
+ if (!pNameAddrNext)
+ {
+ LOCATION(0x7);
+ // we finally delete the tracker here after using it to refresh
+ // all of the names. It is not deleted in the RefreshCompletion
+ // routine anymore!
+ //
+ IF_DBG(NBT_DEBUG_REFRESH)
+ KdPrint(("Nbt:Refresh Done Adapter %X, Name %15.15s<%x>\n",
+ (ULONG)AdapterNumber,pNameAddr->Name,pNameAddr->Name[15]));
+
+ DereferenceTracker(pTracker);
+ NbtConfig.DoingRefreshNow = FALSE;
+
+ }
+
+
+ }
+
+ExitRoutine:
+ CTEMemFree(pContext);
+
+ CTEExReleaseResource(&NbtConfig.Resource);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+RefreshTimeout(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine handles is the timeout handler for name refreshes to
+ WINS. It just queues the request to the Executive worker thread so that
+ the work can be done at non-dispatch level. If there is currently a
+ refresh going on, then the routine simply restarts the timer and
+ exits.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ CTELockHandle OldIrq;
+
+ if (!pTimerQEntry)
+ {
+ return;
+ }
+ else
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (NodeType & BNODE)
+ {
+ // Do not restart the timer
+ CHECK_PTR(pTimerQEntry);
+
+ pTimerQEntry->Flags = 0;
+ NbtConfig.pRefreshTimer = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return;
+ }
+
+ LOCATION(0x10);
+
+
+ if (!NbtConfig.DoingRefreshNow)
+ {
+ // this is a global flag that prevents a second refresh
+ // from starting when one is currently going on.
+ //
+ LOCATION(0x11);
+ NbtConfig.DoingRefreshNow = TRUE;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ CTEQueueForNonDispProcessing(NULL,NULL,NULL,RefreshBegin,NULL);
+
+ } // doing refresh now
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+
+
+ // set any new timeout value and restart the timer
+ //
+ pTimerQEntry->DeltaTime = NbtConfig.MinimumTtl/NbtConfig.RefreshDivisor;
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+RefreshBegin(
+ PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles starting up sending name refreshes to the name server.
+
+ The idea is to set the timeout to T/8 and check for names with the Refresh
+ bit cleared - re-registering those names. At T=4 and T=0, clear all bits
+ and refresh all names. The Inbound code sets the refresh bit when it gets a
+ refresh response from the NS.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ CTELockHandle OldIrq;
+ tNAMEADDR *pNameAddr;
+ NTSTATUS status;
+ tHASHTABLE *pHashTable;
+ PCHAR pScope;
+ LONG i,j;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ ULONG TimeoutCount;
+ tDEVICECONTEXT *pDeviceContext;
+ CTEULONGLONG Adapter;
+ BOOLEAN fTimeToSwitch = FALSE;
+ BOOLEAN fTimeToRefresh = FALSE;
+
+ CTEMemFree(pContext);
+ LOCATION(0x12);
+
+ pScope = NbtConfig.pScope;
+
+ // get the timeout cycle number
+
+ TimeoutCount = NbtConfig.sTimeoutCount++;
+ //
+ // BUG #3094:
+ // Currently, we try to switch back to primary every 1/2 TTl => 3 days, generally.
+ // We try to do this more often - every hour by checking at each timeout
+ // if we have not switched for an hour.
+ //
+ // We take care not to clear the refresh bits in the name on every interval by re-checking
+ // for the T/2 or 0 conditions later.
+ //
+ // Do this before the modulo operation.
+ //
+ fTimeToSwitch = (((NbtConfig.MinimumTtl/NbtConfig.RefreshDivisor) *
+ (TimeoutCount - NbtConfig.LastSwitchTimeoutCount)) >= DEFAULT_SWITCH_TTL);
+
+ IF_DBG(NBT_DEBUG_REFRESH)
+ KdPrint(("Nbt:fTimeToSwitch: %d, MinTtl: %lx, RefDiv: %d, TimeoutCount: %d, LastSwTimeoutCount: %d",
+ fTimeToSwitch, NbtConfig.MinimumTtl, NbtConfig.RefreshDivisor, TimeoutCount, NbtConfig.LastSwitchTimeoutCount));
+
+ NbtConfig.sTimeoutCount %= NbtConfig.RefreshDivisor;
+
+ //
+ // If the refresh timeout has been set to the maximum value then do
+ // not send any refreshes to the name server
+ //
+ if (NbtConfig.MinimumTtl == NBT_MAXIMUM_TTL)
+ {
+ NbtConfig.DoingRefreshNow = FALSE;
+ return;
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // go through the local table clearing the REFRESHED bit and sending
+ // name refreshes to the name server
+ //
+ pHashTable = NbtConfig.pLocalHashTbl;
+
+ // clear the refreshed bits so all names get refreshed if we are
+ // at interval 0 or interval 8/2
+ //
+
+ fTimeToRefresh = ((TimeoutCount == (NbtConfig.RefreshDivisor/2)) || (TimeoutCount == 0));
+
+ if (fTimeToRefresh || fTimeToSwitch)
+ {
+ CTEULONGLONG JustSwitched = 0;
+
+ NbtConfig.LastSwitchTimeoutCount = (USHORT)TimeoutCount;
+
+ for (i=0 ;i < pHashTable->lNumBuckets ;i++ )
+ {
+
+ pHead = &pHashTable->Bucket[i];
+ pEntry = pHead->Flink;
+
+ //
+ // Go through each name in each bucket of the hashtable
+ //
+ while (pEntry != pHead)
+ {
+ PLIST_ENTRY pHead1,pEntry1;
+
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+
+ // don't refresh scope names or names in conflict or that are the
+ // broadcast name "* ", or Quick added names.(since these are
+ // not registered on the network)
+ //
+
+ if (!(pNameAddr->NameTypeState & STATE_RESOLVED) ||
+ (pNameAddr->Name[0] == '*') ||
+ (IsBrowserName(pNameAddr->Name)) ||
+ (pNameAddr->NameTypeState & NAMETYPE_QUICK))
+ {
+ pEntry = pEntry->Flink;
+ continue;
+ }
+
+ // Go through each adapter checking
+ // if a name was not refreshed. If not switch to
+ // the backup WINS for this devicecontext.
+ //
+ pHead1 = &NbtConfig.DeviceContexts;
+ pEntry1 = pHead1->Flink;
+ j = 0;
+ while (pEntry1 != pHead1)
+ {
+
+ Adapter = (CTEULONGLONG)1 << j++;
+
+ pDeviceContext = CONTAINING_RECORD(pEntry1,tDEVICECONTEXT,Linkage);
+ pEntry1 = pEntry1->Flink;
+
+ // if the name was registered on this
+ // adapter...and we have not already switched to the
+ // backup name server, check if we should switch now.
+ //
+ if (pNameAddr->AdapterMask & Adapter)
+ {
+ // if we haven't just switched this adapter to its
+ // backup and...
+ // if the name was not refreshed, then switch to
+ // the backup
+ //
+ // or if the name was refreshed, but
+ // to the backup, try the primary again.
+ //
+ if (!(JustSwitched & Adapter) &&
+ (!(pNameAddr->RefreshMask & Adapter) ||
+ ((pNameAddr->RefreshMask & Adapter) &&
+ (pDeviceContext->RefreshToBackup))))
+ {
+ SwitchToBackup(pDeviceContext);
+ //
+ // keep a bit mask of which adapters have
+ // switched to backup so we don't
+ // switch again and be back where we started.
+ //
+ JustSwitched |= Adapter;
+ }
+
+ }
+
+ }
+
+ // clear the refresh mask, so we can refresh all over
+ // again!
+ CHECK_PTR(pNameAddr);
+
+ //
+ // Dont clear the refresh bits when we are trying to switch (say at T/8).
+ //
+ if (fTimeToRefresh) {
+ pNameAddr->RefreshMask = 0;
+ }
+
+ // next hash table entry
+ pEntry = pEntry->Flink;
+ }
+
+ }
+ }
+
+ // always start at the first name in the hash table. As each name gets
+ // refreshed NextRefresh will be hit to get the next name etc..
+ //
+ NbtConfig.CurrentHashBucket = 0;
+
+ status = STATUS_UNSUCCESSFUL;
+
+
+ //
+ // get the next(first) name in the hash table
+ //
+ GetNextName(NULL,&pNameAddr);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ if (pNameAddr)
+ {
+ LOCATION(0x13);
+ status = StartRefresh(pNameAddr,NULL,TRUE);
+
+ //
+ // If this routine fails then the address element increment done in
+ // GetNextName has to be undone here
+ //
+ if (!NT_SUCCESS(status))
+ {
+ NbtDereferenceAddress(pNameAddr->pAddressEle);
+ NbtConfig.DoingRefreshNow = FALSE;
+ }
+
+ }
+ else
+ {
+ NbtConfig.DoingRefreshNow = 0;
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+RemoteHashTimeout(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine handles deleting names in the Remote Hash table that are
+ old. The basic alorithm scans the table looking at the Timed_out bit.
+ If it is set then the name is deleted, otherwise the bit is set. This
+ means the names can live as long as 2*Timeout or as little as Timeout.
+ So set the Timeout to 6 Minutes and names live 9 minutes +- 3 minutes.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ CTELockHandle OldIrq;
+ tNAMEADDR *pNameAddr;
+ tHASHTABLE *pHashTable;
+ PCHAR pScope;
+ LONG i;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ if (pTimerQEntry)
+ {
+ pScope = NbtConfig.pScope;
+
+ //
+ // go through the remote table deleting names that have timeout bits
+ // set and setting the bits for names that have the bit clear
+ //
+ pHashTable = NbtConfig.pRemoteHashTbl;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ for (i=0;i < pHashTable->lNumBuckets ;i++ )
+ {
+ pHead = &pHashTable->Bucket[i];
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ pEntry = pEntry->Flink;
+ //
+ // do not delete scope entries, and do not delete names that
+ // that are still resolving, and do not delete names that are
+ // being used by someone (refcount > 1)
+ //
+ if ((pNameAddr->TimeOutCount == 0) &&
+ (pNameAddr->NameTypeState & (STATE_RESOLVED | STATE_RELEASED)) &&
+ (pNameAddr->RefCount <= 1))
+ {
+ NbtDereferenceName(pNameAddr);
+ }
+ else
+ { //
+ // don't mark the name as a candidate for deletion if
+ // someone is using it now
+ //
+ if (!(pNameAddr->NameTypeState & NAMETYPE_SCOPE) &&
+ (pNameAddr->RefCount <= 1) &&
+ (pNameAddr->NameTypeState & (STATE_RESOLVED | STATE_RELEASED)))
+ {
+ pNameAddr->TimeOutCount--;
+ }
+
+ }
+
+ }
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // restart the timer
+ //
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ }
+
+ return;
+
+}
+//----------------------------------------------------------------------------
+ VOID
+NextKeepAlive(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN NTSTATUS statuss,
+ IN ULONG Info
+ )
+/*++
+
+Routine Description:
+
+ This routine handles sending subsequent KeepAlives for sessions.
+ This is the "Client Completion" routine of the TdiSend that sends the
+ keep alive on the session.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ tLOWERCONNECTION *pLowerConnLast;
+ tLOWERCONNECTION *pLowerConn;
+ tDEVICECONTEXT *pDeviceContext;
+
+ PUSH_LOCATION(0x92);
+ pDeviceContext = pTracker->pDeviceContext;
+
+ pLowerConnLast = (tLOWERCONNECTION *)pTracker->pClientEle;
+
+ // get the next session to send a keep alive on, if there is one, otherwise
+ // free the session header block.
+ //
+ GetNextKeepAlive(pDeviceContext,
+ &pDeviceContext,
+ pLowerConnLast,
+ &pLowerConn);
+
+ NbtDereferenceLowerConnection(pLowerConnLast);
+
+ if (pLowerConn)
+ {
+
+ pTracker->pDeviceContext = pDeviceContext;
+ pTracker->pClientEle = (tCLIENTELE *)pLowerConn;
+
+ ASSERT((pTracker->SendBuffer.HdrLength + pTracker->SendBuffer.Length) == 4);
+ PUSH_LOCATION(0x91);
+#ifndef VXD
+ // this may wind up the stack if the completion occurs synchronously,
+ // because the completion routine is this routine, so call a routine
+ // that sets up a dpc to to the send, which will not run until this
+ // procedure returns and we get out of raised irql.
+ //
+ NTSendSession(pTracker,
+ pLowerConn,
+ NextKeepAlive);
+#else
+
+ (void) TcpSendSession( pTracker, pLowerConn, NextKeepAlive ) ;
+#endif
+ }
+ else
+ {
+ FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
+ }
+
+
+
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+GetNextKeepAlive(
+ tDEVICECONTEXT *pDeviceContext,
+ tDEVICECONTEXT **ppDeviceContextOut,
+ tLOWERCONNECTION *pLowerConnIn,
+ tLOWERCONNECTION **ppLowerConnOut
+ )
+/*++
+
+Routine Description:
+
+ This routine handles sending session keep Alives to the other end of a
+ connection about once a minute or so.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq2;
+ tLOWERCONNECTION *pLowerConn;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PLIST_ENTRY pHeadDevice;
+ PLIST_ENTRY pEntryDevice;
+
+ //
+ // loop through all the adapter cards looking at all connections
+ //
+ pHeadDevice = &NbtConfig.DeviceContexts;
+ pEntryDevice = &pDeviceContext->Linkage;
+ while (pEntryDevice != pHeadDevice)
+ {
+ pDeviceContext = CONTAINING_RECORD(pEntryDevice,tDEVICECONTEXT,Linkage);
+ pEntryDevice = pEntryDevice->Flink;
+
+ // grab the device context spin lock so that the lower connection
+ // element does not get removed from the Q while we are checking the
+ // connection state
+ //
+ CTESpinLock(pDeviceContext,OldIrq);
+ PUSH_LOCATION(0x90);
+ pHead = &pDeviceContext->LowerConnection;
+ //
+ // get the next lower connection after this one one the list, but
+ // be sure this connection is still on the active list by checking
+ // the state.
+ //
+ // If this connection has been cleaned up in OutOfRsrcKill, then dont trust the linkages.
+ //
+ if (pLowerConnIn &&
+ !pLowerConnIn->OutOfRsrcFlag &&
+ ((pLowerConnIn->State == NBT_SESSION_UP) ||
+ (pLowerConnIn->State == NBT_SESSION_INBOUND)))
+ {
+ pEntry = pLowerConnIn->Linkage.Flink;
+ pLowerConnIn = NULL;
+ }
+ else
+ {
+ pEntry = pHead->Flink;
+ }
+
+ while (pEntry != pHead)
+ {
+
+ pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
+
+ //
+ // Inbound connections can hang around forever in that state if
+ // the session setup message never gets sent, so send keep
+ // alives on those too.
+ //
+ if ((pLowerConn->State == NBT_SESSION_UP) ||
+ (pLowerConn->State == NBT_SESSION_INBOUND))
+ {
+
+ // grab the spin lock, recheck the state and
+ // increment the reference count so that this connection cannot
+ // disappear while the keep alive is being sent and screw up
+ // the linked list.
+ CTESpinLock(pLowerConn,OldIrq2);
+ if ((pLowerConn->State != NBT_SESSION_UP ) &&
+ (pLowerConn->State != NBT_SESSION_INBOUND))
+ {
+ // this connection is probably back on the free connection
+ // list, so we will never satisfy the pEntry = pHead and
+ // loop forever, so just get out and send keepalives on the
+ // next timeout
+ //
+ pEntry = pEntry->Flink;
+ PUSH_LOCATION(0x91);
+ CTESpinFree(pLowerConn,OldIrq2);
+ break;
+
+ }
+ else
+ if (pLowerConn->RefCount >= 3 )
+ {
+ //
+ // already a keep alive on this connection, or we
+ // are currently in the receive handler and do not
+ // need to send a keep alive.
+ //
+ pEntry = pEntry->Flink;
+ PUSH_LOCATION(0x93);
+ CTESpinFree(pLowerConn,OldIrq2);
+ continue;
+ }
+
+ //
+ // found a connection to send a keep alive on
+ //
+ pLowerConn->RefCount++;
+ //
+ // return the current position in the list of connections
+ //
+ *ppLowerConnOut = pLowerConn;
+ *ppDeviceContextOut = pDeviceContext;
+
+ CTESpinFree(pLowerConn,OldIrq2);
+ CTESpinFree(pDeviceContext,OldIrq);
+
+ return;
+
+ }
+
+ pEntry = pEntry->Flink;
+ }
+
+ CTESpinFree(pDeviceContext,OldIrq);
+ }
+ *ppLowerConnOut = NULL;
+ return;
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SessionKeepAliveTimeout(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine handles starting the non dispatch level routine to send
+ keep alives.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ if (pTimerQEntry)
+ {
+ CTEQueueForNonDispProcessing(NULL,NULL,NULL,SessionKeepAliveNonDispatch,NULL);
+
+ // restart the timer
+ //
+ pTimerQEntry->Flags |= TIMER_RESTART;
+
+ }
+ return;
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SessionKeepAliveNonDispatch(
+ PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles sending session keep Alives to the other end of a
+ connection about once a minute or so.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ NTSTATUS status;
+ tLOWERCONNECTION *pLowerConn;
+ tDEVICECONTEXT *pDeviceContext;
+ tSESSIONHDR *pSessionHdr;
+ tDGRAM_SEND_TRACKING *pTracker;
+
+
+ CTEPagedCode();
+ //
+ // go through the list of connections attached to each adapter and
+ // send a session keep alive pdu on each
+ //
+ pDeviceContext = CONTAINING_RECORD(NbtConfig.DeviceContexts.Flink,
+ tDEVICECONTEXT,Linkage);
+
+ // get the next session to send a keep alive on, if there is one, otherwise
+ // free the session header block.
+ //
+ GetNextKeepAlive(pDeviceContext,
+ &pDeviceContext,
+ NULL,
+ &pLowerConn);
+
+ if (pLowerConn)
+ {
+
+ // if we have found a connection, send the first keep alive. Subsequent
+ // keep alives will be sent by the completion routine, NextKeepAlive()
+ //
+
+ pSessionHdr = (tSESSIONHDR *)NbtAllocMem(sizeof(tSESSIONERROR),NBT_TAG('S'));
+ if (!pSessionHdr)
+ {
+ return;
+ }
+
+ // get a tracker structure, which has a SendInfo structure in it
+ status = GetTracker(&pTracker);
+ if (!NT_SUCCESS(status))
+ {
+ CTEMemFree((PVOID)pSessionHdr);
+ return;
+ }
+
+ CHECK_PTR(pTracker);
+ pTracker->SendBuffer.pDgramHdr = (PVOID)pSessionHdr;
+ pTracker->SendBuffer.HdrLength = sizeof(tSESSIONHDR);
+ pTracker->SendBuffer.Length = 0;
+ pTracker->SendBuffer.pBuffer = NULL;
+
+ pSessionHdr->Flags = NBT_SESSION_FLAGS; // always zero
+
+ pTracker->pDeviceContext = pDeviceContext;
+ pTracker->pClientEle = (tCLIENTELE *)pLowerConn;
+ CHECK_PTR(pSessionHdr);
+ pSessionHdr->Type = NBT_SESSION_KEEP_ALIVE; // 85
+ pSessionHdr->Length = 0; // no data following the length byte
+
+ status = TcpSendSession(pTracker,
+ pLowerConn,
+ NextKeepAlive);
+
+
+ }
+
+ CTEMemFree(pContext);
+}
+//----------------------------------------------------------------------------
+ VOID
+IncrementNameStats(
+ IN ULONG StatType,
+ IN BOOLEAN IsNameServer
+ )
+/*++
+
+Routine Description:
+
+ This routine increments statistics on names that resolve either through
+ the WINS or through broadcast.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+
+ //
+ // Increment the stattype if the name server is true, that way we can
+ // differentiate queries and registrations to the name server or not.
+ //
+ if (IsNameServer)
+ {
+ StatType += 2;
+ }
+
+ NameStatsInfo.Stats[StatType]++;
+
+}
+//----------------------------------------------------------------------------
+ VOID
+SaveBcastNameResolved(
+ IN PUCHAR pName
+ )
+/*++
+
+Routine Description:
+
+ This routine saves the name in LIFO list, so we can see the last
+ N names that resolved via broadcast.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ ULONG Index;
+
+ Index = NameStatsInfo.Index;
+
+ CTEMemCopy(&NameStatsInfo.NamesReslvdByBcast[Index],
+ pName,
+ NETBIOS_NAME_SIZE);
+
+ NameStatsInfo.Index++;
+ if (NameStatsInfo.Index >= SIZE_RESOLVD_BY_BCAST_CACHE)
+ {
+ NameStatsInfo.Index = 0;
+ }
+
+}
+
+//
+// These are names that should never be sent to WINS.
+//
+BOOL
+IsBrowserName(
+ IN PCHAR pName
+)
+{
+ CHAR cNameType = pName[NETBIOS_NAME_SIZE - 1];
+
+ return (
+ (cNameType == 0x1E)
+ || (cNameType == 0x1D)
+ || (cNameType == 0x01)
+ );
+}
+
+//
+// Returns the node type that should be used with a request,
+// based on NetBIOS name type. This is intended to help the
+// node to behave like a BNODE for browser names only.
+//
+AppropriateNodeType(
+ IN PCHAR pName,
+ IN ULONG NodeType
+)
+{
+ ULONG LocalNodeType = NodeType;
+
+ if (LocalNodeType & BNODE)
+ {
+ if ( IsBrowserName ( pName ) )
+ {
+ LocalNodeType &= BNODE;
+ }
+ }
+ return LocalNodeType;
+}
+
diff --git a/private/ntos/nbt/nbt/nbtutils.c b/private/ntos/nbt/nbt/nbtutils.c
new file mode 100644
index 000000000..b8bf40090
--- /dev/null
+++ b/private/ntos/nbt/nbt/nbtutils.c
@@ -0,0 +1,2042 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Nbtutils.c
+
+Abstract:
+
+ This file continas a number of utility and support routines for
+ the NBT code.
+
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+
+
+NTSTATUS
+DisableInboundConnections(
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT PLIST_ENTRY pLowerConnFreeHead
+ );
+
+NTSTATUS
+EnableInboundConnections(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PLIST_ENTRY pLowerConnFreeHead
+ );
+
+VOID
+NbtNonDpcFreeAddrObj(
+ IN PVOID pContext
+ );
+
+//#if DBG
+LIST_ENTRY UsedIrps;
+//#endif
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, ConvertDottedDecimalToUlong)
+#pragma CTEMakePageable(PAGE, CloseLowerConnections)
+#pragma CTEMakePageable(PAGE, CountUpperConnections)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//----------------------------------------------------------------------------
+ void
+NbtFreeAddressObj(
+ tADDRESSELE *pBlk)
+
+/*++
+
+Routine Description:
+
+ This routine releases all memory associated with an Address object.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ //
+ // let's come back and do this later when it's not dpc time
+ //
+ CTEQueueForNonDispProcessing(
+ NULL,
+ pBlk,
+ NULL,
+ NbtNonDpcFreeAddrObj,
+ pBlk->pDeviceContext);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NbtNonDpcFreeAddrObj(
+ IN PVOID pContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine releases all memory associated with an Address object.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ tADDRESSELE *pAddress;
+
+ pAddress = (tADDRESSELE *)((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
+
+ if (pAddress)
+ {
+
+#ifndef VXD
+ if (pAddress->SecurityDescriptor)
+ SeDeassignSecurity(&pAddress->SecurityDescriptor);
+#endif
+ // free the address block itself
+ // zero the verify value so that another user of the same memory
+ // block cannot accidently pass in a valid verifier
+
+ pAddress->Verify += 10;
+ CTEMemFree((PVOID)pAddress);
+ }
+
+ CTEMemFree(pContext);
+}
+
+//----------------------------------------------------------------------------
+ void
+NbtFreeClientObj(
+ tCLIENTELE *pBlk)
+
+/*++
+
+Routine Description:
+
+ This routine releases all memory associated with Client object.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+
+{
+
+ if (pBlk)
+ {
+ // zero the verify value so that another user of the same memory
+ // block cannot accidently pass in a valid verifier
+ pBlk->Verify += 10;
+ CTEMemFree((PVOID)pBlk);
+ }
+}
+
+//----------------------------------------------------------------------------
+ void
+FreeConnectionObj(
+ tCONNECTELE *pBlk)
+
+/*++
+
+Routine Description:
+
+ This routine releases all memory associated with a Connection object
+ and then it frees the connection object itself.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+
+{
+
+ if (pBlk)
+ {
+
+ // zero the verify value so that another user of the same memory
+ // block cannot accidently pass in a valid verifier
+ pBlk->Verify += 10;
+ CTEMemFree(pBlk);
+
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ tCLIENTELE *
+NbtAllocateClientBlock(tADDRESSELE *pAddrEle)
+
+/*++
+
+Routine Description:
+
+ This routine allocates a block of memory for a client openning an
+ address. It fills in default values for the block and links the
+ block to the addresslist. The AddressEle spin lock is held when this
+ routine is called.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ tCLIENTELE *pClientElement;
+
+ // allocate memory for the client block
+ pClientElement = (tCLIENTELE *)CTEAllocInitMem(sizeof (tCLIENTELE));
+ if (!pClientElement)
+ {
+ ASSERTMSG("Unable to allocate Memory for a client block\n",
+ pClientElement);
+ return(NULL);
+ }
+ CTEZeroMemory((PVOID)pClientElement,sizeof(tCLIENTELE));
+
+ CTEInitLock(&pClientElement->SpinLock);
+
+ // Set Event handler function pointers to default routines provided by
+ // TDI
+#ifndef VXD
+ pClientElement->evConnect = TdiDefaultConnectHandler;
+ pClientElement->evReceive = TdiDefaultReceiveHandler;
+ pClientElement->evDisconnect = TdiDefaultDisconnectHandler;
+ pClientElement->evError = TdiDefaultErrorHandler;
+ pClientElement->evRcvDgram = TdiDefaultRcvDatagramHandler;
+ pClientElement->evRcvExpedited = TdiDefaultRcvExpeditedHandler;
+ pClientElement->evSendPossible = TdiDefaultSendPossibleHandler;
+#else
+ //
+ // VXD provides no client support for event handlers but does
+ // make use of some of the event handlers itself (for RcvAny processing
+ // and disconnect cleanup).
+ //
+ pClientElement->evConnect = NULL ;
+ pClientElement->evReceive = NULL ;
+ pClientElement->RcvEvContext = NULL ;
+ pClientElement->evDisconnect = NULL ;
+ pClientElement->evError = NULL ;
+ pClientElement->evRcvDgram = NULL ;
+ pClientElement->evRcvExpedited = NULL ;
+ pClientElement->evSendPossible = NULL ;
+#endif
+
+ pClientElement->RefCount = 1;
+ pClientElement->LockNumber = CLIENT_LOCK;
+
+ // there are no rcvs or snds yet
+ InitializeListHead(&pClientElement->RcvDgramHead);
+ InitializeListHead(&pClientElement->ListenHead);
+ InitializeListHead(&pClientElement->SndDgrams);
+ InitializeListHead(&pClientElement->ConnectActive);
+ InitializeListHead(&pClientElement->ConnectHead);
+#ifdef VXD
+ InitializeListHead(&pClientElement->RcvAnyHead);
+ pClientElement->fDeregistered = FALSE ;
+#endif
+ pClientElement->pIrp = NULL;
+
+ // copy a special value into the verify long so that we can verify
+ // connection ptrs passed back from the application
+ pClientElement->Verify = NBT_VERIFY_CLIENT;
+
+ // back link the client block to the Address element.
+ pClientElement->pAddress = (PVOID)pAddrEle;
+
+ // put the new Client element block on the end of the linked list tied to
+ // the address element
+ InsertTailList(&pAddrEle->ClientHead,&pClientElement->Linkage);
+
+ return(pClientElement);
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtAddPermanentName(
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds the node permanent name to the local name table. This
+ is the node's MAC address padded out to 16 bytes with zeros.
+
+Arguments:
+ DeviceContext - Adapter to add permanent
+ pIrp - Irp (optional) to complete after name has been added
+
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ NTSTATUS status;
+ TDI_REQUEST Request;
+ TA_NETBIOS_ADDRESS Address;
+ UCHAR pName[NETBIOS_NAME_SIZE];
+ USHORT uType;
+ CTELockHandle OldIrq;
+ tNAMEADDR *pNameAddr;
+ tCLIENTELE *pClientEle;
+
+ CTEZeroMemory(pName,NETBIOS_NAME_SIZE);
+ CTEMemCopy(&pName[10],&pDeviceContext->MacAddress.Address[0],sizeof(tMAC_ADDRESS));
+
+ //
+ // be sure the name has not already been added
+ //
+ if (pDeviceContext->pPermClient)
+ {
+ if (CTEMemEqu(pDeviceContext->pPermClient->pAddress->pNameAddr->Name,
+ pName,
+ NETBIOS_NAME_SIZE))
+ {
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ NbtRemovePermanentName(pDeviceContext);
+ }
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ //
+ // check if the name is already in the hash table
+ //
+ status = FindInHashTable(
+ pNbtGlobConfig->pLocalHashTbl,
+ pName,
+ NbtConfig.pScope,
+ &pNameAddr);
+
+ if (NT_SUCCESS(status))
+ {
+ //
+ // create client block and link to addresslist
+ // pass back the client block address as a handle for future reference
+ // to the client
+ //
+
+ pClientEle = NbtAllocateClientBlock((tADDRESSELE *)pNameAddr->pAddressEle);
+ if (!pClientEle)
+ return(STATUS_INSUFFICIENT_RESOURCES);
+
+ pNameAddr->pAddressEle->RefCount++;
+ //
+ // reset the ip address incase the the address got set to loop back
+ // by a client releasing and re-openning the permanent name while there
+ // was no ip address for this node.
+ //
+ pNameAddr->IpAddress = pDeviceContext->IpAddress;
+
+ // keep track of which adapter this name is registered against.
+ pClientEle->pDeviceContext = (PVOID)pDeviceContext;
+
+ // turn on the adapter's bit in the adapter Mask and set the
+ // re-register flag so we register the name out the new
+ // adapter.
+ //
+ pNameAddr->AdapterMask |= pDeviceContext->AdapterNumber;
+
+ pNameAddr->NameTypeState |= NAMETYPE_QUICK;
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt: Adding Permanent name to existing name in table %15.15s<%X> \n",
+ pName,(UCHAR)pName[15]));
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ // make up the Request data structure from the IRP info
+ Request.Handle.AddressHandle = NULL;
+
+ //
+ // Make it a Quick name so it does not get registered on the net
+ //
+ Address.TAAddressCount = 1;
+ Address.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ Address.Address[0].AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
+ Address.Address[0].Address[0].NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE;
+
+ CTEMemCopy(Address.Address[0].Address[0].NetbiosName,pName,NETBIOS_NAME_SIZE);
+
+ status = NbtOpenAddress(&Request,
+ (PTA_ADDRESS)&Address.Address[0],
+ pDeviceContext->IpAddress,
+ NULL,
+ pDeviceContext,
+ NULL);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ pClientEle = (tCLIENTELE *)Request.Handle.AddressHandle;
+
+ }
+
+ //
+ // save the client element so we can remove the permanent name later
+ // if required
+ //
+ if (NT_SUCCESS(status))
+ {
+ pDeviceContext->pPermClient = pClientEle;
+#ifdef VXD
+ //
+ // 0th element is for perm. name: store it.
+ //
+ pDeviceContext->pNameTable[0] = pClientEle;
+#endif
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return(status);
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+NbtRemovePermanentName(
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine remomves the node permanent name to the local name table.
+
+Arguments:
+ DeviceContext - Adapter to add permanent
+ pIrp - Irp (optional) to complete after name has been added
+
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ NTSTATUS status;
+ tNAMEADDR *pNameAddr;
+ CTELockHandle OldIrq;
+ tCLIENTELE *pClientEle;
+ tADDRESSELE *pAddressEle;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ if (pDeviceContext->pPermClient)
+ {
+
+ //
+ // We need to free the client and set the perm name ptr to null
+ //
+ pClientEle = pDeviceContext->pPermClient;
+ pDeviceContext->pPermClient = NULL;
+
+#ifdef VXD
+ pDeviceContext->pNameTable[0] = NULL;
+#endif
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ NbtDereferenceClient(pClientEle);
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+ConvertDottedDecimalToUlong(
+ IN PUCHAR pInString,
+ OUT PULONG IpAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts a unicode dotted decimal IP address into
+ a 4 element array with each element being USHORT.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+ USHORT i;
+ ULONG value;
+ int iSum =0;
+ ULONG k = 0;
+ UCHAR Chr;
+ UCHAR pArray[4];
+
+ CTEPagedCode();
+ pArray[0] = 0;
+
+ // go through each character in the string, skipping "periods", converting
+ // to integer by subtracting the value of '0'
+ //
+ while ((Chr = *pInString++) && (Chr != ' ') )
+ {
+ if (Chr == '.')
+ {
+ // be sure not to overflow a byte.
+ if (iSum <= 0xFF)
+ pArray[k] = iSum;
+ else
+ return(STATUS_UNSUCCESSFUL);
+
+ // check for too many periods in the address
+ if (++k > 3)
+ return STATUS_UNSUCCESSFUL;
+
+ pArray[k] = 0;
+ iSum = 0;
+ }
+ else
+ {
+ Chr = Chr - '0';
+
+ // be sure character is a number 0..9
+ if ((Chr < 0) || (Chr > 9))
+ return(STATUS_UNSUCCESSFUL);
+
+ iSum = iSum*10 + Chr;
+ }
+ }
+
+ // save the last sum in the byte and be sure there are 4 pieces to the
+ // address
+ if ((iSum <= 0xFF) && (k == 3))
+ pArray[k] = iSum;
+ else
+ return(STATUS_UNSUCCESSFUL);
+
+ // now convert to a ULONG, in network order...
+ value = 0;
+
+ // go through the array of bytes and concatenate into a ULONG
+ for (i=0; i < 4; i++ )
+ {
+ value = (value << 8) + pArray[i];
+ }
+ *IpAddress = value;
+
+ return(STATUS_SUCCESS);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtInitQ(
+ PLIST_ENTRY pListHead,
+ LONG iSizeBuffer,
+ LONG iNumBuffers
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory blocks for doubly linked lists and links
+ them to a list.
+
+Arguments:
+ ppListHead - a ptr to a ptr to the list head to add buffer to
+ iSizeBuffer - size of the buffer to add to the list head
+ iNumBuffers - the number of buffers to add to the queue
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ int i;
+ PLIST_ENTRY pBuffer;
+
+ // NOTE THAT THIS ASSUMES THAT THE LINKAGE PTRS FOR EACH BLOCK ARE AT
+ // THE START OF THE BLOCK - so it will not work correctly if
+ // the various types in types.h change to move "Linkage" to a position
+ // other than at the start of each structure to be chained
+
+ for (i=0;i<iNumBuffers ;i++ )
+ {
+ pBuffer =(PLIST_ENTRY)CTEAllocInitMem(iSizeBuffer);
+ if (!pBuffer)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ else
+ {
+ InsertHeadList(pListHead,pBuffer);
+ }
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtInitTrackerQ(
+ PLIST_ENTRY pListHead,
+ LONG iNumBuffers
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory blocks for doubly linked lists and links
+ them to a list.
+
+Arguments:
+ ppListHead - a ptr to a ptr to the list head to add buffer to
+ iNumBuffers - the number of buffers to add to the queue
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ int i;
+ tDGRAM_SEND_TRACKING *pTracker;
+
+ for (i=0;i<iNumBuffers ;i++ )
+ {
+ pTracker = NbtAllocTracker();
+ if (!pTracker)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ else
+ {
+ NbtConfig.iCurrentNumBuff[eNBT_DGRAM_TRACKER]++;
+ InsertHeadList(pListHead,&pTracker->Linkage);
+ }
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ tDGRAM_SEND_TRACKING *
+NbtAllocTracker(
+ IN VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates memory for several of the structures attached to
+ the dgram tracking list, so that this memory does not need to be
+ allocated and freed for each send.
+
+Arguments:
+
+ ppListHead - a ptr to a ptr to the list head
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ PLIST_ENTRY pEntry;
+ tDGRAM_SEND_TRACKING *pTracker;
+ PTRANSPORT_ADDRESS pTransportAddr;
+ ULONG TotalSize;
+
+ //
+ // allocate all the tracker memory as one block and then divy it up later
+ // into the various buffers
+ //
+ TotalSize = sizeof(tDGRAM_SEND_TRACKING)
+ + sizeof(TDI_CONNECTION_INFORMATION)
+ + sizeof(TRANSPORT_ADDRESS) -1
+ + NbtConfig.SizeTransportAddress;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)CTEAllocInitMem(TotalSize);
+
+ if (pTracker)
+ {
+ CTEZeroMemory(pTracker,TotalSize);
+
+ pTracker->pSendInfo = (PTDI_CONNECTION_INFORMATION)((PUCHAR)pTracker
+ + sizeof(tDGRAM_SEND_TRACKING));
+
+ // fill in the connection information - especially the Remote address
+ // structure
+
+ pTracker->pSendInfo->RemoteAddressLength = sizeof(TRANSPORT_ADDRESS) -1
+ + pNbtGlobConfig->SizeTransportAddress;
+
+ // allocate the remote address structure
+ pTransportAddr = (PTRANSPORT_ADDRESS)((PUCHAR)pTracker->pSendInfo
+ + sizeof(TDI_CONNECTION_INFORMATION));
+
+ // fill in the remote address
+ pTransportAddr->TAAddressCount = 1;
+ pTransportAddr->Address[0].AddressLength = NbtConfig.SizeTransportAddress;
+ pTransportAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+ ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->sin_port = NBT_NAMESERVICE_UDP_PORT;
+ ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->in_addr = 0L;
+
+ // put a ptr to this address structure into the sendinfo structure
+ pTracker->pSendInfo->RemoteAddress = (PVOID)pTransportAddr;
+
+ // Empty the list of trackers linked to this one
+ InitializeListHead(&pTracker->TrackerList);
+
+ }
+
+ return(pTracker);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtGetBuffer(
+ PLIST_ENTRY pListHead,
+ PLIST_ENTRY *ppListEntry,
+ enum eBUFFER_TYPES eBuffType)
+
+/*++
+
+Routine Description:
+
+ This routine tries to get a memory block and if it fails it allocates
+ another set of buffers.
+
+Arguments:
+ ppListHead - a ptr to a ptr to the list head to add buffer to
+ iSizeBuffer - size of the buffer to add to the list head
+ iNumBuffers - the number of buffers to add to the queue
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ NTSTATUS status;
+
+ if (IsListEmpty(pListHead))
+ {
+ // check if we are allowed to allocate more memory blocks
+ if (NbtConfig.iCurrentNumBuff[eBuffType] >=
+ pNbtGlobConfig->iMaxNumBuff[eBuffType] )
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // no memory blocks, so allocate another one
+ status = NbtInitQ(
+ pListHead,
+ pNbtGlobConfig->iBufferSize[eBuffType],
+ 1);
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+
+ NbtConfig.iCurrentNumBuff[eBuffType]++;
+
+ *ppListEntry = RemoveHeadList(pListHead);
+ }
+ else
+ *ppListEntry = RemoveHeadList(pListHead);
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+GetNetBiosNameFromTransportAddress(
+ IN PTA_NETBIOS_ADDRESS pTransAddr,
+ OUT PCHAR *pName,
+ OUT PULONG pNameLen,
+ OUT PULONG pNameType
+ )
+/*++
+
+Routine Description
+
+ This routine handles deciphering the weird transport address syntax
+ to retrieve the netbios name out of that address.
+
+Arguments:
+
+
+Return Values:
+
+ NTSTATUS - status of the request
+
+--*/
+{
+
+ ULONG Diff;
+
+ //
+ // name could be longer than 16 bytes (dns name), but make sure it's at
+ // least 16 bytes (sizeof(TDI_ADDRESS_NETBIOS = 16 + sizeof(USHORT))
+ //
+ if (pTransAddr->Address[0].AddressLength < sizeof(TDI_ADDRESS_NETBIOS))
+ {
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ *pName = (PCHAR)pTransAddr->Address[0].Address[0].NetbiosName;
+
+ Diff = sizeof(TDI_ADDRESS_NETBIOS) - NETBIOS_NAME_SIZE;
+
+ *pNameLen = (ULONG)pTransAddr->Address[0].AddressLength - Diff;
+
+ *pNameType = pTransAddr->Address[0].Address[0].NetbiosNameType;
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+ConvertToAscii(
+ IN PCHAR pNameHdr,
+ IN LONG NumBytes,
+ OUT PCHAR pName,
+ OUT PCHAR *pScope,
+ OUT PULONG pNameSize
+ )
+/*++
+
+Routine Description:
+
+ This routine converts half ascii to normal ascii and then appends the scope
+ onto the end of the name to make a full name again.
+
+Arguments:
+ NumBytes - the total number of bytes in the message - may include
+ more than just the name itself
+
+Return Value:
+
+ NTSTATUS - success or not
+ This routine returns the length of the name in half ascii format including
+ the null at the end, but NOT including the length byte at the beginning.
+ For a non-scoped name it returns 33.
+
+ It converts the name to ascii and puts 16 bytes into pName, then it returns
+ pScope as the Ptr to the scope that is still in pNameHdr.
+
+
+--*/
+{
+ LONG i;
+ int iIndex;
+ LONG lValue;
+ ULONG UNALIGNED *pHdr;
+ PUCHAR pTmp;
+
+ // the first bytes should be 32 (0x20) - the length of the half
+ // ascii name
+ //
+ if ((*pNameHdr == NETBIOS_NAME_SIZE*2) && (NumBytes > NETBIOS_NAME_SIZE*2))
+ {
+ pHdr = (ULONG UNALIGNED *)++pNameHdr; // to increment past the length byte
+
+ // the Half AScii portion of the netbios name is always 32 bytes long
+ for (i=0; i < NETBIOS_NAME_SIZE*2 ;i +=4 )
+ {
+ lValue = *pHdr - 0x41414141; // four A's
+ pHdr++;
+ lValue = ((lValue & 0x0F000000) >> 16) +
+ ((lValue & 0x0F0000) >> 4) +
+ ((lValue & 0x0F00) >> 8) +
+ ((lValue & 0x0F) << 4);
+ *(PUSHORT)pName = (USHORT)lValue;
+ ((PUSHORT)pName)++;
+
+ }
+
+ // verify that the name has the correct format...i.e. it is one or more
+ // labels each starting with the length byte for the label and the whole
+ // thing terminated with a 0 byte (for the root node name length of zero).
+ // count the length of the scope. pName should be pointing at the first
+ // length byte of the scope now, and pHdr should be pointing to the
+ // first byte after the half ascii name.
+ iIndex = 0;
+
+ //
+ // Store the address of the start of the scope in the netbios name
+ // (if one is present). If there is no scope present in the name, then
+ // pHdr must be pointing to the NULL byte.
+ //
+ pTmp = (PUCHAR)pHdr;
+
+ // cannot used structured exception handling at raised IRQl and expect
+ // it to work, since the mapper will bugcheck
+ while (iIndex < (NumBytes - NETBIOS_NAME_SIZE*2-1) && *pTmp)
+ {
+ pTmp++;
+ iIndex++;
+ }
+ iIndex++; // to include the null at the end.
+
+ // check for an overflow on the maximum length of 256 bytes
+ if (iIndex > (MAX_DNS_NAME_LENGTH-NETBIOS_NAME_SIZE-1))
+ {
+ // the name is too long..probably badly formed
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ *pScope = (PUCHAR)pHdr;
+
+ *pNameSize = NETBIOS_NAME_SIZE*2 + iIndex;
+
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ return(STATUS_UNSUCCESSFUL);
+ }
+}
+
+
+//----------------------------------------------------------------------------
+ PCHAR
+ConvertToHalfAscii(
+ OUT PCHAR pDest,
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN ULONG uScopeSize
+ )
+/*++
+
+Routine Description:
+
+ This routine converts ascii to half ascii and appends the scope on the
+ end
+
+Arguments:
+
+
+Return Value:
+
+ the address of the next byte in the destination after the the name
+ has been converted and copied
+
+--*/
+{
+ LONG i;
+
+ // the first byte of the name is the length field = 2*16
+ *pDest++ = ((UCHAR)NETBIOS_NAME_SIZE << 1);
+
+ // step through name converting ascii to half ascii, for 32 times
+ for (i=0; i < NETBIOS_NAME_SIZE ;i++ )
+ {
+ *pDest++ = ((UCHAR)*pName >> 4) + 'A';
+ *pDest++ = (*pName++ & 0x0F) + 'A';
+ }
+ //
+ // put the length of the scope into the next byte followed by the
+ // scope itself. For 1 length scopes (the normal case), writing
+ // the zero(for the end of the scope is all that is needed).
+ //
+ if (uScopeSize > 1)
+ {
+ CTEMemCopy(pDest,pScope,uScopeSize);
+
+ pDest = pDest + uScopeSize;
+ }
+ else
+ {
+ *pDest++ = 0;
+ }
+
+
+ // return the address of the next byte of the destination
+ return(pDest);
+}
+
+
+//----------------------------------------------------------------------------
+ ULONG
+Nbt_inet_addr(
+ IN PCHAR pName
+ )
+/*++
+
+Routine Description:
+
+ This routine converts ascii ipaddr (11.101.4.25) into a ULONG. This is
+ based on the inet_addr code in winsock
+
+Arguments:
+ pName - the string containing the ipaddress
+
+Return Value:
+
+ the ipaddress as a ULONG if it's a valid ipaddress. Otherwise, 0.
+
+--*/
+{
+
+ PCHAR pStr;
+ int i;
+ int len, fieldLen;
+ int fieldsDone;
+ ULONG IpAddress;
+ BYTE ByteVal;
+ PCHAR pIpPtr;
+ BOOLEAN fDotFound;
+ BOOLEAN fieldOk;
+
+
+ pStr = pName;
+ len = 0;
+ pIpPtr = (PCHAR)&IpAddress;
+ pIpPtr += 3; // so that we store in network order
+ fieldsDone=0;
+
+ //
+ // the 11.101.4.25 format can be atmost 15 chars, and pName is guaranteed
+ // to be at least 16 chars long (how convenient!!). Convert the string to
+ // a ULONG.
+ //
+ while(len < NETBIOS_NAME_SIZE)
+ {
+ fieldLen=0;
+ fieldOk = FALSE;
+ ByteVal = 0;
+ fDotFound = FALSE;
+
+ //
+ // This loop traverses each of the four fields (max len of each
+ // field is 3, plus 1 for the '.'
+ //
+ while (fieldLen < 4)
+ {
+ if (*pStr >='0' && *pStr <='9')
+ {
+ ByteVal = (ByteVal*10) + (*pStr - '0');
+ fieldOk = TRUE;
+ }
+
+ else if (*pStr == '.' || *pStr == ' ' || *pStr == '\0')
+ {
+ *pIpPtr = ByteVal;
+ pIpPtr--;
+ fieldsDone++;
+
+ if (*pStr == '.')
+ fDotFound = TRUE;
+
+ // if we got a space or 0, assume it's the 4th field
+ if (*pStr == ' ' || *pStr == '\0')
+ {
+ break;
+ }
+ }
+
+ // unacceptable char: can't be ipaddr
+ else
+ {
+ return(0);
+ }
+
+ pStr++;
+ len++;
+ fieldLen++;
+
+ // if we found the dot, we are done with this field: go to the next one
+ if (fDotFound)
+ break;
+ }
+
+ // this field wasn't ok (e.g. "11.101..4" or "11.101.4." etc.)
+ if (!fieldOk)
+ {
+ return(0);
+ }
+
+ // if we are done with all 4 fields, we are done with the outer loop too
+ if ( fieldsDone == 4)
+ break;
+
+ if (!fDotFound)
+ {
+ return(0);
+ }
+ }
+
+ //
+ // make sure the remaining chars are spaces or 0's (i.e. don't allow
+ // 11.101.4.25xyz to succeed)
+ //
+ for (i=len; i<NETBIOS_NAME_SIZE; i++, pStr++)
+ {
+ if (*pStr != ' ' && *pStr != '\0')
+ {
+ return(0);
+ }
+ }
+
+ return( IpAddress );
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+GetTracker(
+ OUT tDGRAM_SEND_TRACKING **ppTracker)
+/*++
+Routine Description:
+
+ This Routine gets a Tracker data structure to track sending a datagram
+ or session packet.
+
+Arguments:
+
+Return Value:
+
+ BOOLEAN - TRUE if IRQL is too high
+
+--*/
+
+{
+ PLIST_ENTRY pListEntry;
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ tDGRAM_SEND_TRACKING *pTracker;
+
+ CTESpinLock(&NbtConfig,OldIrq);
+ if (!IsListEmpty(&NbtConfig.DgramTrackerFreeQ))
+ {
+ pListEntry = RemoveHeadList(&NbtConfig.DgramTrackerFreeQ);
+ CTESpinFree(&NbtConfig,OldIrq);
+
+ pTracker = CONTAINING_RECORD(pListEntry,tDGRAM_SEND_TRACKING,Linkage);
+
+ //
+ // Do these initializations here - there was a problem where this tracker's transactionId
+ // would be set to 0x1A1A (indirectly thru unions), and used as such since the check in CreatePdu
+ // is for a 0 TransactionId field in the tracker returned from this function.
+ //
+#if DBG
+ pTracker->Verify = NBT_VERIFY_TRACKER;
+ pTracker->pClientIrp = (PVOID)0x1A1A1A1A;
+ pTracker->pConnEle = (PVOID)0x1A1A1A1A;
+ pTracker->SendBuffer.HdrLength = 0x1A1A1A1A;
+ pTracker->SendBuffer.pDgramHdr = (PVOID)0x1A1A1A1A;
+ pTracker->SendBuffer.Length = 0x1A1A1A1A;
+ pTracker->SendBuffer.pBuffer = (PVOID)0x1A1A1A1A;
+ pTracker->pDeviceContext = (PVOID)0x1A1A1A1A;
+ pTracker->pTimer = (PVOID)0x1A1A1A1A;
+ pTracker->RefCount = 0x1A1A1A1A;
+ pTracker->pDestName = (PVOID)0x1A1A1A1A;
+ pTracker->pNameAddr = (PVOID)0x1A1A1A1A;
+#ifdef VXD
+ pTracker->pchDomainName = (PVOID)0x1A1A1A1A;
+#endif
+ pTracker->pTimeout = (PVOID)0x1A1A1A1A;
+ pTracker->SrcIpAddress = 0x1A1A1A1A;
+ pTracker->CompletionRoutine = (PVOID)0x1A1A1A1A;
+ pTracker->Flags = 0x1A1A;
+#endif
+ // clear any list of trackers Q'd to this tracker
+ InitializeListHead(&pTracker->TrackerList);
+ pTracker->Connect.pTimer = NULL;
+ pTracker->pClientIrp = NULL;
+ pTracker->TransactionId = 0;
+ pTracker->Flags = 0;
+
+ InitializeListHead(&pTracker->Linkage);
+ status = STATUS_SUCCESS;
+
+ }
+ else
+ {
+
+ if (NbtConfig.iCurrentNumBuff[eNBT_DGRAM_TRACKER] >=
+ NbtConfig.iMaxNumBuff[eNBT_DGRAM_TRACKER])
+ {
+ CTESpinFree(&NbtConfig,OldIrq);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pTracker = NbtAllocTracker();
+
+ CTESpinFree(&NbtConfig,OldIrq);
+ if (!pTracker)
+ {
+ KdPrint(("GetTracker: No more trackers available, failing request!\n")) ;
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+#if DBG
+ pTracker->Verify = NBT_VERIFY_TRACKER;
+ pTracker->pClientIrp = (PVOID)0x1A1A1A1A;
+ pTracker->pConnEle = (PVOID)0x1A1A1A1A;
+ pTracker->SendBuffer.HdrLength = 0x1A1A1A1A;
+ pTracker->SendBuffer.pDgramHdr = (PVOID)0x1A1A1A1A;
+ pTracker->SendBuffer.Length = 0x1A1A1A1A;
+ pTracker->SendBuffer.pBuffer = (PVOID)0x1A1A1A1A;
+ pTracker->pDeviceContext = (PVOID)0x1A1A1A1A;
+ pTracker->pTimer = (PVOID)0x1A1A1A1A;
+ pTracker->RefCount = 0x1A1A1A1A;
+ pTracker->pDestName = (PVOID)0x1A1A1A1A;
+ pTracker->pNameAddr = (PVOID)0x1A1A1A1A;
+#ifdef VXD
+ pTracker->pchDomainName = (PVOID)0x1A1A1A1A;
+#endif
+ pTracker->pTimeout = (PVOID)0x1A1A1A1A;
+ pTracker->SrcIpAddress = 0x1A1A1A1A;
+ pTracker->CompletionRoutine = (PVOID)0x1A1A1A1A;
+ pTracker->Flags = 0x1A1A;
+#endif
+ NbtConfig.iCurrentNumBuff[eNBT_DGRAM_TRACKER]++;
+ pTracker->Connect.pTimer = NULL ;
+ InitializeListHead(&pTracker->Linkage);
+ status = STATUS_SUCCESS;
+ }
+
+
+ }
+//#if DBG
+ // keep tracker on a used list for debug
+ if (NT_SUCCESS(status))
+ {
+ //ADD_TO_LIST(&UsedTrackers,&pTracker->DebugLinkage);
+ }
+//#endif
+
+ *ppTracker = pTracker;
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+#ifndef VXD
+ NTSTATUS
+GetIrp(
+ OUT PIRP *ppIrp)
+/*++
+Routine Description:
+
+ This Routine gets an Irp from the free queue or it allocates another one
+ the queue is empty.
+
+Arguments:
+
+Return Value:
+
+ BOOLEAN - TRUE if IRQL is too high
+
+--*/
+
+{
+ PLIST_ENTRY pListEntry;
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ tDEVICECONTEXT *pDeviceContext;
+ PIRP pIrp;
+
+ // get an Irp from the list
+ CTESpinLock(&NbtConfig,OldIrq);
+ status = STATUS_SUCCESS;
+ if (!IsListEmpty(&NbtConfig.IrpFreeList))
+ {
+ pListEntry = RemoveHeadList(&NbtConfig.IrpFreeList);
+ *ppIrp = CONTAINING_RECORD(pListEntry,IRP,Tail.Overlay.ListEntry);
+ }
+ else
+ {
+ // check if we are allowed to allocate more memory blocks
+ if (NbtConfig.iCurrentNumBuff[eNBT_FREE_IRPS] >=
+ NbtConfig.iMaxNumBuff[eNBT_FREE_IRPS] )
+ {
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+
+ // use the first device in the list of adapter since we need to know
+ // the stack size of the Irp we are creating. It is possible to
+ // get here before we have put the first device on the context Q,
+ // especially for proxy operation, so check if the list is empty
+ // or not first.
+ //
+ if (IsListEmpty(&NbtConfig.DeviceContexts))
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ pListEntry = NbtConfig.DeviceContexts.Flink;
+ pDeviceContext = CONTAINING_RECORD(pListEntry,tDEVICECONTEXT,Linkage);
+
+ pIrp = NTAllocateNbtIrp(&pDeviceContext->DeviceObject);
+
+ if (!pIrp)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ *ppIrp = pIrp;
+
+ //
+ // Irp allocated - Increment the #
+ //
+ NbtConfig.iCurrentNumBuff[eNBT_FREE_IRPS]++;
+ }
+ }
+
+ }
+
+ }
+
+ CTESpinFree(&NbtConfig,OldIrq);
+//#if DBG
+ if (status == STATUS_SUCCESS)
+ {
+ ADD_TO_LIST(&UsedIrps,&(*ppIrp)->ThreadListEntry);
+ }
+//#endif
+
+ return(status);
+}
+#endif //!VXD
+
+//----------------------------------------------------------------------------
+ ULONG
+CountLocalNames(IN tNBTCONFIG *pNbtConfig
+ )
+/*++
+Routine Description:
+
+ This Routine counts the number of names in the local name table.
+
+Arguments:
+
+Return Value:
+
+ ULONG - the number of names
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ ULONG Count;
+ tNAMEADDR *pNameAddr;
+ LONG i;
+
+ Count = 0;
+
+ for (i=0;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ )
+ {
+ pHead = &NbtConfig.pLocalHashTbl->Bucket[i];
+ pEntry = pHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ //
+ // don't want unresolved names, or the broadcast name
+ //
+ if (!(pNameAddr->NameTypeState & STATE_RESOLVING) &&
+ (pNameAddr->Name[0] != '*'))
+ {
+ Count++;
+ }
+ }
+ }
+
+ return(Count);
+}
+//----------------------------------------------------------------------------
+ ULONG
+CountUpperConnections(
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+Routine Description:
+
+ This Routine counts the number of upper connections that have been created
+ in preparation for creating an equivalent number of lower connections.
+
+
+Arguments:
+
+Return Value:
+
+ ULONG - the number of names
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PLIST_ENTRY pClientHead;
+ PLIST_ENTRY pConnHead;
+ PLIST_ENTRY pClientEntry;
+ PLIST_ENTRY pConnEntry;
+ ULONG CountConnections = 0;
+ tADDRESSELE *pAddressEle;
+ tCLIENTELE *pClient;
+
+ CTEPagedCode();
+ if (!IsListEmpty(&NbtConfig.AddressHead))
+ {
+ // get the list of addresses for this device
+ pHead = &NbtConfig.AddressHead;
+ pEntry = pHead->Flink;
+
+ while (pEntry != pHead)
+ {
+ pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
+ pClientHead = &pAddressEle->ClientHead;
+ pClientEntry = pClientHead->Flink;
+ while (pClientEntry != pClientHead)
+ {
+ pClient = CONTAINING_RECORD(pClientEntry,tCLIENTELE,Linkage);
+ pConnHead = &pClient->ConnectHead;
+ pConnEntry = pConnHead->Flink;
+ while (pConnEntry != pConnHead)
+ {
+ CountConnections++;
+ pConnEntry = pConnEntry->Flink;
+ }
+ pClientEntry = pClientEntry->Flink;
+ }
+ pEntry = pEntry->Flink;
+ }
+
+ }
+
+ return(CountConnections);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+DisableInboundConnections(
+ IN tDEVICECONTEXT *pDeviceContext,
+ OUT PLIST_ENTRY pLowerConnFreeHead
+ )
+/*++
+
+Routine Description:
+
+ This routine checks the devicecontext for open connections and sets
+ the Lower Connection free list to empty.
+
+Arguments:
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ PLIST_ENTRY pLowerHead;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ CTESpinLock(pDeviceContext,OldIrq);
+ {
+ PLIST_ENTRY pLowerHead;
+
+ if (!IsListEmpty(&pDeviceContext->LowerConnFreeHead))
+ {
+ pLowerHead = &pDeviceContext->LowerConnFreeHead;
+ pLowerConnFreeHead->Flink = pLowerHead->Flink;
+ pLowerConnFreeHead->Blink = pLowerHead->Blink;
+
+ // hook the list head and tail to the new head
+ pLowerHead->Flink->Blink = pLowerConnFreeHead;
+ pLowerHead->Blink->Flink = pLowerConnFreeHead;
+
+ InitializeListHead(&pDeviceContext->LowerConnFreeHead);
+ }
+ else
+ {
+ InitializeListHead(pLowerConnFreeHead);
+ }
+ }
+
+ MarkForCloseLowerConnections(pDeviceContext,OldIrq1,OldIrq);
+
+ return(STATUS_SUCCESS);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+EnableInboundConnections(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PLIST_ENTRY pLowerConnFreeHead
+ )
+/*++
+
+Routine Description:
+
+ This routine checks each device context to see if there are any open
+ connections, and returns SUCCESS if there are.
+
+Arguments:
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(pDeviceContext,OldIrq);
+ pDeviceContext->LowerConnFreeHead.Flink = pLowerConnFreeHead->Flink;
+ pDeviceContext->LowerConnFreeHead.Blink = pLowerConnFreeHead->Blink;
+ CTESpinFree(pDeviceContext,OldIrq);
+ return(STATUS_SUCCESS);
+
+}
+//----------------------------------------------------------------------------
+ ULONG
+CloseLowerConnections(
+ IN PLIST_ENTRY pLowerConnFreeHead
+ )
+/*++
+
+Routine Description:
+
+ This routine checks each device context to see if there are any open
+ connections, and returns SUCCESS if there are.
+
+Arguments:
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ tLOWERCONNECTION *pLowerConn;
+ CTELockHandle OldIrq;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PLIST_ENTRY pNextEntry;
+ ULONG Count=0;
+
+ CTEPagedCode();
+
+ pHead = pLowerConnFreeHead;
+
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
+ pNextEntry = pEntry->Flink;
+ RemoveEntryList(pEntry);
+ pEntry = pNextEntry;
+ Count++;
+
+ //
+ // close the lower connection with the transport
+ //
+ //DereferenceObject((PVOID *)pLowerConn->pFileObject);
+ //TdiCloseConnection(pLowerConn);
+
+ NbtDereferenceLowerConnection(pLowerConn);
+
+ }
+ return(Count);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+MarkForCloseLowerConnections(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN CTELockHandle OldIrqJoint,
+ IN CTELockHandle OldIrqDevice
+ )
+/*++
+
+Routine Description:
+
+ This routine checks each device context to see if there are any open
+ connections, and returns SUCCESS if there are.
+
+Arguments:
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ tLOWERCONNECTION *pLowerConn;
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq2;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ ULONG Count=0;
+ tLOWERCONNECTION **pList;
+
+ pHead = &pDeviceContext->LowerConnection;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
+ pLowerConn->DestroyConnection = TRUE;
+
+ pEntry = pEntry->Flink;
+ Count++;
+ }
+
+ // ******************************************
+ // NOTE: The code after this point can probably be deleted
+ // because TCP should disconnect all open connections when it
+ // is notified of the address change. Just use this code for test.
+ //
+ if (Count)
+ {
+ pList = NbtAllocMem(Count * sizeof(tLOWERCONNECTION *),NBT_TAG('T'));
+ if (pList)
+ {
+ //
+ // save the lower connection pointers in a list
+ // until they can be deleted.
+ //
+ pHead = &pDeviceContext->LowerConnection;
+ pEntry = pHead->Flink;
+ Count = 0;
+ while (pEntry != pHead)
+ {
+ pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
+// if (pLowerConn->State == NBT_SESSION_UP)
+ {
+ *pList = pLowerConn;
+ pList++;
+ InterlockedIncrement(&pLowerConn->RefCount);
+ pEntry = pEntry->Flink;
+ Count++;
+ }
+ }
+
+ CTESpinFree(pDeviceContext,OldIrqDevice);
+ CTESpinFree(&NbtConfig.JointLock,OldIrqJoint);
+
+ //
+ // now go through the list of Lower connections to see which are
+ // still up and issue disconnects on them.
+ //
+ while (Count--)
+ {
+ pLowerConn = (tLOWERCONNECTION *)*(--pList);
+ CTESpinLock(pLowerConn,OldIrq);
+
+ //
+ // In the connecting state the TCP connection is being
+ // setup.
+ //
+ if ((pLowerConn->State == NBT_SESSION_UP) ||
+ (pLowerConn->State == NBT_CONNECTING))
+ {
+
+ tCLIENTELE *pClientEle;
+ tCONNECTELE *pConnEle;
+
+ if (pLowerConn->State == NBT_CONNECTING)
+ {
+ // CleanupAfterDisconnect expects this ref count
+ // to be 2, meaning that it got connected, so increment
+ // here
+ pLowerConn->RefCount++;
+ }
+
+ pClientEle = pLowerConn->pUpperConnection->pClientEle;
+ pLowerConn->State = NBT_DISCONNECTING;
+ pConnEle = pLowerConn->pUpperConnection;
+ pConnEle->state = NBT_DISCONNECTED;
+ pConnEle->pLowerConnId = NULL;
+ pLowerConn->pUpperConnection = NULL;
+ SetStateProc(pLowerConn,RejectAnyData);
+
+ CTESpinFree(pLowerConn,OldIrq);
+
+ DereferenceIfNotInRcvHandler(pConnEle,pLowerConn);
+
+ if ( pClientEle->evDisconnect )
+ {
+ status = (*pClientEle->evDisconnect)(pClientEle->DiscEvContext,
+ pConnEle->ConnectContext,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ TDI_DISCONNECT_ABORT);
+ }
+
+ // this should kill of the connection when the irp
+ // completes by calling CleanupAfterDisconnect.
+ //
+#ifndef VXD
+ status = DisconnectLower(pLowerConn,
+ NBT_SESSION_UP,
+ TDI_DISCONNECT_ABORT,
+ &DefaultDisconnectTimeout,
+ TRUE);
+#else
+ // Vxd can't wait for the disconnect
+ status = DisconnectLower(pLowerConn,
+ NBT_SESSION_UP,
+ TDI_DISCONNECT_ABORT,
+ &DefaultDisconnectTimeout,
+ FALSE);
+
+#endif
+ }
+ else
+ if (pLowerConn->State == NBT_IDLE)
+ {
+ tCONNECTELE *pConnEle;
+
+ CTESpinFree(pLowerConn,OldIrq);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pConnEle = pLowerConn->pUpperConnection;
+
+ if (pConnEle)
+ {
+ CTESpinLock(pConnEle,OldIrq2);
+ //
+ // this makes a best effort to find the connection and
+ // and cancel it. Anything not cancelled will eventually
+ // fail with a bad ret code from the transport which is
+ // ok too.
+ //
+ status = CleanupConnectingState(pConnEle,pDeviceContext,
+ &OldIrq2,&OldIrq);
+ CTESpinFree(pConnEle,OldIrq2);
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ else
+ CTESpinFree(pLowerConn,OldIrq);
+
+ //
+ // remove the reference added above when the list was
+ // created.
+ //
+ NbtDereferenceLowerConnection(pLowerConn);
+ }
+
+ CTEMemFree(pList);
+ return;
+
+ }
+ }
+
+ CTESpinFree(pDeviceContext,OldIrqDevice);
+ CTESpinFree(&NbtConfig.JointLock,OldIrqJoint);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtInitConnQ(
+ PLIST_ENTRY pListHead,
+ int iSizeBuffer,
+ int iNumConnections,
+ tDEVICECONTEXT *pDeviceContext)
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory blocks for connections to the transport
+ provider and then sets up connections with the provider.
+
+Arguments:
+ ppListHead - a ptr to a ptr to the list head to add buffer to
+ iSizeBuffer - size of the buffer to add to the list head
+ iNumConnections - the number of buffers to add to the queue
+ pDeviceContext - ptr to the devicecontext
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ USHORT i;
+ tLOWERCONNECTION *pLowerConn;
+ NTSTATUS status;
+
+ CTEPagedCode();
+ for (i=0;i < iNumConnections ;i++ )
+ {
+ pLowerConn =(tLOWERCONNECTION *)NbtAllocMem((ULONG)sizeof(tLOWERCONNECTION),NBT_TAG('U'));
+ if (!pLowerConn)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ else
+ {
+ CTEZeroMemory((PVOID)pLowerConn,sizeof(tLOWERCONNECTION));
+
+ // open a connection with the transport provider
+ status = NbtTdiOpenConnection(
+ pLowerConn,
+ pDeviceContext);
+
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint( ("Nbt:OpenConnection failed! Status:%X,", status));
+ return(status);
+ }
+
+ // associate the connection with the session address object
+ status = NbtTdiAssociateConnection(
+ pLowerConn->pFileObject,
+#ifndef VXD
+ pDeviceContext->hSession);
+#else
+ pDeviceContext->pSessionFileObject);
+#endif
+
+
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint( ("Nbt:Associate failed! Status:%X,", status));
+ return(status);
+ }
+
+ // link the lower connection to the device context so we can free
+ // the lower connections back to their correct device free Q's.
+ pLowerConn->pDeviceContext = (PVOID)pDeviceContext;
+ InsertHeadList(pListHead,&pLowerConn->Linkage);
+ }
+ }
+ return(STATUS_SUCCESS);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+ReRegisterLocalNames(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine re-registers names with WINS when DHCP changes the IP
+ address.
+
+Arguments:
+
+ pDeviceContext - ptr to the devicecontext
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ NTSTATUS status;
+ tTIMERQENTRY *pTimerEntry;
+ CTELockHandle OldIrq;
+ LONG i;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tNAMEADDR *pNameAddr;
+
+
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pTimerEntry = NbtConfig.pRefreshTimer;
+
+ if (pTimerEntry)
+ {
+ status = StopTimer(pTimerEntry,NULL,NULL);
+ NbtConfig.pRefreshTimer = NULL;
+ }
+
+ //
+ // restart timer and use
+ // the initial refresh rate until we can contact the name server
+ //
+ NbtConfig.MinimumTtl = NbtConfig.InitialRefreshTimeout;
+ NbtConfig.RefreshDivisor = REFRESH_DIVISOR;
+
+ //
+ // set this to 3 so that refreshBegin will refresh to the primary and
+ // then switch to backup on the next refresh interval if it doesn't
+ // get through.
+ //
+ NbtConfig.sTimeoutCount = 3;
+
+ status = StartTimer(
+ NbtConfig.InitialRefreshTimeout/NbtConfig.RefreshDivisor,
+ NULL, // context value
+ NULL, // context2 value
+ RefreshTimeout,
+ NULL,
+ NULL,
+ 0,
+ &pTimerEntry);
+
+ if ( !NT_SUCCESS( status ) )
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return status ;
+ }
+
+ NbtConfig.pRefreshTimer = pTimerEntry;
+
+ for (i=0 ;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ )
+ {
+
+ pHead = &NbtConfig.pLocalHashTbl->Bucket[i];
+ pEntry = pHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ //
+ // set so that nextrefresh finds the name and does a refresh
+ //
+ if (!(pNameAddr->NameTypeState & STATE_RESOLVED) ||
+ (pNameAddr->Name[0] == '*') ||
+ (pNameAddr->NameTypeState & NAMETYPE_QUICK))
+ {
+ continue;
+ }
+ else
+ {
+ pNameAddr->RefreshMask = 0;
+ pNameAddr->Ttl = NbtConfig.InitialRefreshTimeout;
+ }
+
+ }
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // start a refresh if there isn't one currently going on
+ // Note that there is a time window here that if the refresh is
+ // currently going on then, some names will not get refreshed with
+ // the new IpAddress right away, but have to wait to the next
+ // refresh interval. It seems that this is a rather unlikely
+ // scenario and given the low probability of DHCP changing the
+ // address it makes even less sense to add the code to handle that
+ // case.
+ //
+ RefreshTimeout(NULL,NULL,NbtConfig.pRefreshTimer);
+
+ return(STATUS_SUCCESS);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+LockedStopTimer(
+ tTIMERQENTRY **ppTimer)
+
+/*++
+
+Routine Description:
+
+ This routine stops the refresh timer if it is going.
+
+Arguments:
+
+ pDeviceContext - ptr to the devicecontext
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ tTIMERQENTRY TimerEntry;
+ CTELockHandle OldIrq;
+
+ //
+ // Check if there is a refresh timer since this node could be changing
+ // from a Bnode to an Hnode, where the Bnode does not have a refresh timer
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (*ppTimer)
+ {
+ StopTimer(*ppTimer,NULL,NULL);
+ *ppTimer = NULL;
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return(STATUS_SUCCESS);
+}
diff --git a/private/ntos/nbt/nbt/parse.c b/private/ntos/nbt/nbt/parse.c
new file mode 100644
index 000000000..ae6a33839
--- /dev/null
+++ b/private/ntos/nbt/nbt/parse.c
@@ -0,0 +1,4140 @@
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ parse.c
+
+Abstract:
+
+ This source contains the functions that parse the lmhosts file.
+
+Author:
+
+ Jim Stewart May 2, 1993
+
+Revision History:
+
+
+--*/
+
+#include "types.h"
+#ifndef VXD
+#include <nbtioctl.h>
+#endif
+#include "nbtprocs.h"
+#include "hosts.h"
+#include <ctype.h>
+#include <string.h>
+
+#ifdef VXD
+extern BOOL fInInit;
+extern BOOLEAN CachePrimed;
+#endif
+
+//
+// Returns 0 if equal, 1 if not equal. Used to avoid using c-runtime
+//
+#define strncmp( pch1, pch2, length ) \
+ (!CTEMemEqu( pch1, pch2, length ) )
+
+
+//
+// Private Definitions
+//
+// As an lmhosts file is parsed, a #INCLUDE directive is interpreted
+// according to the INCLUDE_STATE at that instance. This state is
+// determined by the #BEGIN_ALTERNATE and #END_ALTERNATE directives.
+//
+//
+typedef enum _INCLUDE_STATE
+{
+
+ MustInclude = 0, // shouldn't fail
+ TryToInclude, // in alternate block
+ SkipInclude // satisfied alternate
+ // block
+} INCLUDE_STATE;
+
+
+//
+// LmpGetTokens() parses a line and returns the tokens in the following
+// order:
+//
+typedef enum _TOKEN_ORDER_
+{
+
+ IpAddress = 0, // first token
+ NbName, // 2nd token
+ GroupName, // 3rd or 4th token
+ NotUsed, // #PRE, if any
+ NotUsed2, // #NOFNR, if any
+ MaxTokens // this must be last
+
+} TOKEN_ORDER;
+
+
+//
+// As each line in an lmhosts file is parsed, it is classified into one of
+// the categories enumerated below.
+//
+// However, Preload is a special member of the enum.
+//
+//
+typedef enum _TYPE_OF_LINE
+{
+
+ Comment = 0x0000, // comment line
+ Ordinary = 0x0001, // ip_addr NetBIOS name
+ Domain = 0x0002, // ... #DOM:name
+ Include = 0x0003, // #INCLUDE file
+ BeginAlternate = 0x0004, // #BEGIN_ALTERNATE
+ EndAlternate = 0x0005, // #END_ALTERNATE
+ ErrorLine = 0x0006, // Error in line
+
+ NoFNR = 0x4000, // ... #NOFNR
+ Preload = 0x8000 // ... #PRE
+
+} TYPE_OF_LINE;
+
+
+//
+// In an lmhosts file, the following are recognized as keywords:
+//
+// #BEGIN_ALTERNATE #END_ALTERNATE #PRE
+// #DOM: #INCLUDE
+//
+// Information about each keyword is kept in a KEYWORD structure.
+//
+//
+typedef struct _KEYWORD
+{ // reserved keyword
+
+ char *k_string; // NULL terminated
+ size_t k_strlen; // length of token
+ TYPE_OF_LINE k_type; // type of line
+ int k_noperands; // max operands on line
+
+} KEYWORD, *PKEYWORD;
+
+
+typedef struct _LINE_CHARACTERISTICS_
+{
+
+ int l_category:4; // enum _TYPE_OF_LINE
+ int l_preload:1; // marked with #PRE ?
+ unsigned int l_nofnr:1; // marked with #NOFNR
+
+} LINE_CHARACTERISTICS, *PLINE_CHARACTERISTICS;
+
+
+
+
+
+//
+// Local Variables
+//
+//
+// In an lmhosts file, the token '#' in any column usually denotes that
+// the rest of the line is to be ignored. However, a '#' may also be the
+// first character of a keyword.
+//
+// Keywords are divided into two groups:
+//
+// 1. decorations that must either be the 3rd or 4th token of a line,
+// 2. directives that must begin in column 0,
+//
+//
+KEYWORD Decoration[] =
+{
+
+ DOMAIN_TOKEN, sizeof(DOMAIN_TOKEN) - 1, Domain, 5,
+ PRELOAD_TOKEN, sizeof(PRELOAD_TOKEN) - 1, Preload, 5,
+ NOFNR_TOKEN, sizeof(NOFNR_TOKEN) -1, NoFNR, 5,
+
+ NULL, 0 // must be last
+};
+
+
+KEYWORD Directive[] =
+{
+
+ INCLUDE_TOKEN, sizeof(INCLUDE_TOKEN) - 1, Include, 2,
+ BEG_ALT_TOKEN, sizeof(BEG_ALT_TOKEN) - 1, BeginAlternate, 1,
+ END_ALT_TOKEN, sizeof(END_ALT_TOKEN) - 1, EndAlternate, 1,
+
+ NULL, 0 // must be last
+};
+
+//
+// Local Variables
+//
+//
+// Each preloaded lmhosts entry corresponds to NSUFFIXES NetBIOS names,
+// each with a 16th byte from Suffix[].
+//
+// For example, an lmhosts entry specifying "popcorn" causes the
+// following NetBIOS names to be added to nbt.sys' name cache:
+//
+// "POPCORN "
+// "POPCORN 0x0"
+// "POPCORN 0x3"
+//
+//
+#define NSUFFIXES 3
+UCHAR Suffix[] = { // LAN Manager Component
+ 0x20, // server
+ 0x0, // redirector
+ 0x03 // messenger
+};
+
+#ifndef VXD
+//
+// this structure tracks names queries that are passed up to user mode
+// to resolve via DnsQueries
+//
+tDNS_QUERIES DnsQueries;
+tCHECK_ADDR CheckAddr;
+#endif
+
+//
+// this structure tracks names queries that are passed to the LMhost processing
+// to resolve.
+//
+tLMHOST_QUERIES LmHostQueries;
+
+tDOMAIN_LIST DomainNames;
+
+//
+// Local (Private) Functions
+//
+LINE_CHARACTERISTICS
+LmpGetTokens (
+ IN OUT PUCHAR line,
+ OUT PUCHAR *token,
+ IN OUT int *pnumtokens
+ );
+
+PKEYWORD
+LmpIsKeyWord (
+ IN PUCHAR string,
+ IN PKEYWORD table
+ );
+
+BOOLEAN
+LmpBreakRecursion(
+ IN PUCHAR path,
+ IN PUCHAR target
+ );
+
+LONG
+HandleSpecial(
+ IN char **pch);
+
+ULONG
+AddToDomainList (
+ IN PUCHAR pName,
+ IN ULONG IpAddress,
+ IN PLIST_ENTRY pDomainHead
+ );
+
+VOID
+ChangeStateInRemoteTable (
+ IN tIPLIST *pIpList,
+ OUT PVOID *pContext
+ );
+
+VOID
+ChangeStateOfName (
+ IN ULONG IpAddress,
+ IN NBT_WORK_ITEM_CONTEXT *Context,
+ OUT PVOID *pContext,
+ IN BOOLEAN LmHosts
+ );
+
+VOID
+LmHostTimeout(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ );
+
+VOID
+TimeoutQEntries(
+ IN PLIST_ENTRY pHeadList,
+ IN PLIST_ENTRY TmpHead,
+ OUT USHORT *pFlags
+ );
+
+VOID
+StartLmHostTimer(
+ tDGRAM_SEND_TRACKING *pTracker,
+ NBT_WORK_ITEM_CONTEXT *pContext
+ );
+
+NTSTATUS
+GetNameToFind(
+ OUT PUCHAR pName
+ );
+
+VOID
+GetContext (
+ OUT PVOID *pContext
+ );
+
+VOID
+MakeNewListCurrent (
+ PLIST_ENTRY pTmpDomainList
+ );
+
+VOID
+RemoveNameAndCompleteReq (
+ IN NBT_WORK_ITEM_CONTEXT *pContext,
+ IN NTSTATUS status
+ );
+
+PCHAR
+Nbtstrcat( PUCHAR pch, PUCHAR pCat, LONG Len );
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, LmGetIpAddr)
+#pragma CTEMakePageable(PAGE, HandleSpecial)
+#pragma CTEMakePageable(PAGE, LmpGetTokens)
+#pragma CTEMakePageable(PAGE, LmpIsKeyWord)
+#pragma CTEMakePageable(PAGE, LmpBreakRecursion)
+#pragma CTEMakePageable(PAGE, AddToDomainList)
+#pragma CTEMakePageable(PAGE, LmExpandName)
+#pragma CTEMakePageable(PAGE, LmInclude)
+#pragma CTEMakePageable(PAGE, LmGetFullPath)
+#pragma CTEMakePageable(PAGE, PrimeCache)
+#pragma CTEMakePageable(PAGE, ScanLmHostFile)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//----------------------------------------------------------------------------
+
+unsigned long
+LmGetIpAddr (
+ IN PUCHAR path,
+ IN PUCHAR target,
+ IN BOOLEAN recurse,
+ OUT BOOLEAN *bFindName
+ )
+
+/*++
+
+Routine Description:
+
+ This function searches the file for an lmhosts entry that can be
+ mapped to the second level encoding. It then returns the ip address
+ specified in that entry.
+
+ This function is called recursively, via LmInclude() !!
+
+Arguments:
+
+ path - a fully specified path to a lmhosts file
+ target - the unencoded 16 byte NetBIOS name to look for
+ recurse - TRUE if #INCLUDE directives should be obeyed
+
+Return Value:
+
+ The ip address (network byte order), or 0 if no appropriate entry was
+ found.
+
+ Note that in most contexts (but not here), ip address 0 signifies
+ "this host."
+
+--*/
+
+
+{
+ PUCHAR buffer;
+ PLM_FILE pfile;
+ NTSTATUS status;
+ int count, nwords;
+ INCLUDE_STATE incstate;
+ PUCHAR token[MaxTokens];
+ LINE_CHARACTERISTICS current;
+ unsigned long inaddr, retval;
+ UCHAR temp[NETBIOS_NAME_SIZE+1];
+
+ CTEPagedCode();
+ //
+ // Check for infinitely recursive name lookup in a #INCLUDE.
+ //
+ if (LmpBreakRecursion(path, target) == TRUE)
+ {
+ return((unsigned long)0);
+ }
+
+#ifdef VXD
+ //
+ // if we came here via nbtstat -R and InDos is set, report error: user
+ // can try nbtstat -R again. (since nbtstat can only be run from DOS box,
+ // can InDos be ever set??? Might as well play safe)
+ //
+ if ( !fInInit && GetInDosFlag() )
+ {
+ return(0);
+ }
+#endif
+
+ pfile = LmOpenFile(path);
+
+ if (!pfile)
+ {
+ return((unsigned long) 0);
+ }
+
+ *bFindName = FALSE;
+ inaddr = 0;
+ incstate = MustInclude;
+
+ while (buffer = LmFgets(pfile, &count))
+ {
+
+ nwords = MaxTokens;
+ current = LmpGetTokens(buffer, token, &nwords);
+
+ switch ((ULONG)current.l_category)
+ {
+ case ErrorLine:
+ continue;
+
+ case Domain:
+ case Ordinary:
+ if (current.l_preload ||
+ ((nwords - 1) < NbName))
+ {
+ continue;
+ }
+ break;
+
+ case Include:
+ if (!recurse || (incstate == SkipInclude) || (nwords < 2))
+ {
+ continue;
+ }
+
+ retval = LmInclude(token[1], LmGetIpAddr, target, bFindName);
+
+ if (retval == 0)
+ {
+
+ if (incstate == TryToInclude)
+ {
+ incstate = SkipInclude;
+ }
+ continue;
+ }
+ else if (retval == -1)
+ {
+
+ if (incstate == MustInclude)
+ {
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("NBT: can't #INCLUDE \"%s\"", token[1]));
+ }
+ continue;
+ }
+ inaddr = retval;
+ goto found;
+
+ case BeginAlternate:
+ ASSERT(nwords == 1);
+ incstate = TryToInclude;
+ continue;
+
+ case EndAlternate:
+ ASSERT(nwords == 1);
+ incstate = MustInclude;
+ continue;
+
+ default:
+ continue;
+ }
+
+ if (strlen(token[NbName]) == (NETBIOS_NAME_SIZE))
+ {
+ if (strncmp(token[NbName], target, (NETBIOS_NAME_SIZE)) != 0)
+ {
+ continue;
+ }
+ } else
+ {
+ //
+ // attempt to match, in a case insensitive manner, the first 15
+ // bytes of the lmhosts entry with the target name.
+ //
+ LmExpandName(temp, token[NbName], 0);
+
+ if (strncmp(temp, target, NETBIOS_NAME_SIZE - 1) != 0)
+ {
+ continue;
+ }
+ }
+
+ if (current.l_nofnr)
+ {
+ *bFindName = TRUE;
+ }
+ status = ConvertDottedDecimalToUlong(token[IpAddress],&inaddr);
+ if (!NT_SUCCESS(status))
+ {
+ inaddr = 0;
+ }
+ break;
+ }
+
+found:
+ status = LmCloseFile(pfile);
+
+ ASSERT(status == STATUS_SUCCESS);
+
+ if (!NT_SUCCESS(status))
+ {
+ *bFindName = FALSE;
+ }
+
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("NBT: LmGetIpAddr(\"%15.15s<%X>\") = %X\n",target,target[15],inaddr));
+
+
+ return(inaddr);
+} // LmGetIpAddr
+
+
+//----------------------------------------------------------------------------
+LONG
+HandleSpecial(
+ IN CHAR **pch)
+
+/*++
+
+Routine Description:
+
+ This function converts ASCII hex into a ULONG.
+
+Arguments:
+
+
+Return Value:
+
+ The ip address (network byte order), or 0 if no appropriate entry was
+ found.
+
+ Note that in most contexts (but not here), ip address 0 signifies
+ "this host."
+
+--*/
+
+
+{
+ int sval;
+ int rval;
+ char *sp = *pch;
+ int i;
+
+ CTEPagedCode();
+ sp++;
+ switch (*sp)
+ {
+ case '\\':
+ // the second character is also a \ so return a \ and set pch to
+ // point to the next character (\)
+ //
+ *pch = sp;
+ return((int)'\\');
+
+ default:
+
+ // convert some number of characters to hex and increment pch
+ // the expected format is "\0x03"
+ //
+// sscanf(sp, "%2x%n", &sval, &rval);
+
+ sval = 0;
+ rval = 0;
+ sp++;
+
+ // check for the 0x part of the hex number
+ if (*sp != 'x')
+ {
+ *pch = sp;
+ return(-1);
+ }
+ sp++;
+ for (i=0;(( i<2 ) && *sp) ;i++ )
+ {
+ if (*sp != ' ')
+ {
+ // convert from ASCII to hex, allowing capitals too
+ //
+ if (*sp >= 'a')
+ {
+ sval = *sp - 'a' + 10 + sval*16;
+ }
+ else
+ if (*sp >= 'A')
+ {
+ sval = *sp - 'A' + 10 + sval*16;
+ }
+ else
+ {
+ sval = *sp - '0' + sval*16;
+ }
+ sp++;
+ rval++;
+ }
+ else
+ break;
+ }
+
+ if (rval < 1)
+ {
+ *pch = sp;
+ return(-1);
+ }
+
+ *pch += (rval+2); // remember to account for the characters 0 and x
+
+ return(sval);
+
+ }
+}
+
+#define LMHASSERT(s) if (!(s)) \
+{ retval.l_category = ErrorLine; return(retval); }
+
+//----------------------------------------------------------------------------
+
+LINE_CHARACTERISTICS
+LmpGetTokens (
+ IN OUT PUCHAR line,
+ OUT PUCHAR *token,
+ IN OUT int *pnumtokens
+ )
+
+/*++
+
+Routine Description:
+
+ This function parses a line for tokens. A maximum of *pnumtokens
+ are collected.
+
+Arguments:
+
+ line - pointer to the NULL terminated line to parse
+ token - an array of pointers to tokens collected
+ *pnumtokens - on input, number of elements in the array, token[];
+ on output, number of tokens collected in token[]
+
+Return Value:
+
+ The characteristics of this lmhosts line.
+
+Notes:
+
+ 1. Each token must be separated by white space. Hence, the keyword
+ "#PRE" in the following line won't be recognized:
+
+ 11.1.12.132 lothair#PRE
+
+ 2. Any ordinary line can be decorated with a "#PRE", a "#DOM:name" or
+ both. Hence, the following lines must all be recognized:
+
+ 111.21.112.3 kernel #DOM:ntwins #PRE
+ 111.21.112.4 orville #PRE #DOM:ntdev
+ 111.21.112.7 cliffv4 #DOM:ntlan
+ 111.21.112.132 lothair #PRE
+
+--*/
+
+
+{
+ enum _PARSE
+ { // current fsm state
+
+ StartofLine,
+ WhiteSpace,
+ AmidstToken
+
+ } state;
+
+ PUCHAR pch; // current fsm input
+ PUCHAR och;
+ PKEYWORD keyword;
+ int index, maxtokens, quoted, rchar;
+ LINE_CHARACTERISTICS retval;
+
+ CTEPagedCode();
+ CTEZeroMemory(token, *pnumtokens * sizeof(PUCHAR *));
+
+ state = StartofLine;
+ retval.l_category = Ordinary;
+ retval.l_preload = 0;
+ retval.l_nofnr = 0;
+ maxtokens = *pnumtokens;
+ index = 0;
+ quoted = 0;
+
+ for (pch = line; *pch; pch++)
+ {
+ switch (*pch)
+ {
+
+ //
+ // does the '#' signify the start of a reserved keyword, or the
+ // start of a comment ?
+ //
+ //
+ case '#':
+ if (quoted)
+ {
+ *och++ = *pch;
+ continue;
+ }
+ keyword = LmpIsKeyWord(
+ pch,
+ (state == StartofLine) ? Directive : Decoration);
+
+ if (keyword)
+ {
+ state = AmidstToken;
+ maxtokens = keyword->k_noperands;
+
+ switch (keyword->k_type)
+ {
+ case NoFNR:
+ retval.l_nofnr = 1;
+ continue;
+
+ case Preload:
+ retval.l_preload = 1;
+ continue;
+
+ default:
+ LMHASSERT(maxtokens <= *pnumtokens);
+ LMHASSERT(index < maxtokens);
+
+ token[index++] = pch;
+ retval.l_category = keyword->k_type;
+ continue;
+ }
+
+ LMHASSERT(0);
+ }
+
+ if (state == StartofLine)
+ {
+ retval.l_category = Comment;
+ }
+ /* fall through */
+
+ case '\r':
+ case '\n':
+ *pch = (UCHAR) NULL;
+ if (quoted)
+ {
+ *och = (UCHAR) NULL;
+ }
+ goto done;
+
+ case ' ':
+ case '\t':
+ if (quoted)
+ {
+ *och++ = *pch;
+ continue;
+ }
+ if (state == AmidstToken)
+ {
+ state = WhiteSpace;
+ *pch = (UCHAR) NULL;
+
+ if (index == maxtokens)
+ {
+ goto done;
+ }
+ }
+ continue;
+
+ case '"':
+ if ((state == AmidstToken) && quoted)
+ {
+ state = WhiteSpace;
+ quoted = 0;
+ *pch = (UCHAR) NULL;
+ *och = (UCHAR) NULL;
+
+ if (index == maxtokens)
+ {
+ goto done;
+ }
+ continue;
+ }
+
+ state = AmidstToken;
+ quoted = 1;
+ LMHASSERT(maxtokens <= *pnumtokens);
+ LMHASSERT(index < maxtokens);
+ token[index++] = pch + 1;
+ och = pch + 1;
+ continue;
+
+ case '\\':
+ if (quoted)
+ {
+ rchar = HandleSpecial(&pch);
+ if (rchar == -1)
+ {
+ retval.l_category = ErrorLine;
+ return(retval);
+ }
+ *och++ = (UCHAR)rchar;
+ //
+ // put null on end of string
+ //
+
+ continue;
+ }
+
+ default:
+ if (quoted)
+ {
+ *och++ = *pch;
+ continue;
+ }
+ if (state == AmidstToken)
+ {
+ continue;
+ }
+
+ state = AmidstToken;
+
+ LMHASSERT(maxtokens <= *pnumtokens);
+ LMHASSERT(index < maxtokens);
+ token[index++] = pch;
+ continue;
+ }
+ }
+
+done:
+ //
+ // if there is no name on the line, then return an error
+ //
+ if (index <= NbName)
+ {
+ retval.l_category = ErrorLine;
+ }
+ ASSERT(!*pch);
+ ASSERT(maxtokens <= *pnumtokens);
+ ASSERT(index <= *pnumtokens);
+
+ *pnumtokens = index;
+ return(retval);
+} // LmpGetTokens
+
+
+
+//----------------------------------------------------------------------------
+
+PKEYWORD
+LmpIsKeyWord (
+ IN PUCHAR string,
+ IN PKEYWORD table
+ )
+
+/*++
+
+Routine Description:
+
+ This function determines whether the string is a reserved keyword.
+
+Arguments:
+
+ string - the string to search
+ table - an array of keywords to look for
+
+Return Value:
+
+ A pointer to the relevant keyword object, or NULL if unsuccessful
+
+--*/
+
+
+{
+ size_t limit;
+ PKEYWORD special;
+
+ CTEPagedCode();
+ limit = strlen(string);
+
+ for (special = table; special->k_string; special++)
+ {
+
+ if (limit < special->k_strlen)
+ {
+ continue;
+ }
+
+ if ((limit >= special->k_strlen) &&
+ !strncmp(string, special->k_string, special->k_strlen))
+ {
+
+ return(special);
+ }
+ }
+
+ return((PKEYWORD) NULL);
+} // LmpIsKeyWord
+
+
+
+//----------------------------------------------------------------------------
+
+BOOLEAN
+LmpBreakRecursion(
+ IN PUCHAR path,
+ IN PUCHAR target
+ )
+/*++
+
+Routine Description:
+
+ This function checks that the file name we are about to open
+ does not use the target name of this search, which would
+ cause an infinite lookup loop.
+
+Arguments:
+
+ path - a fully specified path to a lmhosts file
+ target - the unencoded 16 byte NetBIOS name to look for
+
+Return Value:
+
+ TRUE if the UNC server name in the file path is the same as the
+ target of this search. FALSE otherwise.
+
+Notes:
+
+ This function does not detect redirected drives.
+
+--*/
+
+
+{
+ PCHAR keystring = "\\DosDevices\\UNC\\";
+ PCHAR servername[NETBIOS_NAME_SIZE+1]; // for null on end
+ PCHAR marker1;
+ PCHAR marker2;
+ PCHAR marker3;
+ BOOLEAN retval = FALSE;
+ tNAMEADDR *pNameAddr;
+ USHORT uType;
+
+ CTEPagedCode();
+ //
+ // Check for and extract the UNC server name
+ //
+ if (strlen(path) > strlen(keystring))
+ {
+ // check that the name is a unc name
+ if (strncmp(path, keystring, strlen(keystring)) == 0)
+ {
+ // the end of the \DosDevices\Unc\ string
+ marker1 = path + strlen(keystring);
+
+ // the end of the whole path
+ marker3 = &path[strlen(path)-1];
+
+ // the end of the server name
+ marker2 = strchr(marker1,'\\');
+
+ if (marker2 != marker3)
+ {
+ *marker2 = '\0';
+
+ //
+ // attempt to match, in a case insensitive manner, the
+ // first 15 bytes of the lmhosts entry with the target
+ // name.
+ //
+ LmExpandName((PUCHAR)servername, marker1, 0);
+
+ if (strncmp((PUCHAR)servername,target,NETBIOS_NAME_SIZE - 1) == 0)
+ {
+ //
+ // break the recursion
+ //
+ retval = TRUE;
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("Nbt:Not including Lmhosts #include because of recursive name %s\n",
+ servername));
+ }
+ else
+ {
+ //
+ // check if the name has been preloaded in the cache, and
+ // if not, fail the request so we can't get into a loop
+ // trying to include the remote file while trying to
+ // resolve the remote name
+ //
+ pNameAddr = FindName(NBT_REMOTE,
+ (PCHAR)servername,
+ NbtConfig.pScope,
+ &uType);
+
+ if (!pNameAddr || !(pNameAddr->NameTypeState & PRELOADED) )
+ {
+ //
+ // break the recursion
+ //
+ retval = TRUE;
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("Nbt:Not including Lmhosts #include because name not Preloaded %s\n",
+ servername));
+ }
+ }
+ *marker2 = '\\';
+ }
+ }
+
+ }
+
+ return(retval);
+}
+
+//----------------------------------------------------------------------------
+ tNAMEADDR *
+FindInDomainList (
+ IN PUCHAR pName,
+ IN PLIST_ENTRY pDomainHead
+ )
+
+/*++
+
+Routine Description:
+
+ This function finds a name in the domain list passed in.
+
+Arguments:
+
+ name to find
+ head of list to look on
+
+Return Value:
+
+ ptr to pNameaddr
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tNAMEADDR *pNameAddr;
+
+ pHead = pEntry = pDomainHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ if (strncmp(pNameAddr->Name,pName,NETBIOS_NAME_SIZE) == 0)
+ {
+ return(pNameAddr);
+ }
+ }
+
+ return(NULL);
+}
+
+//----------------------------------------------------------------------------
+ ULONG
+AddToDomainList (
+ IN PUCHAR pName,
+ IN ULONG IpAddress,
+ IN PLIST_ENTRY pDomainHead
+ )
+
+/*++
+
+Routine Description:
+
+ This function adds a name and ip address to the list of domains that
+ are stored in a list.
+
+
+Arguments:
+
+Return Value:
+
+
+--*/
+
+
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tNAMEADDR *pNameAddr=NULL;
+ ULONG *pIpAddr;
+
+
+ CTEPagedCode();
+
+ pHead = pEntry = pDomainHead;
+
+ if (!IsListEmpty(pDomainHead))
+ {
+ pNameAddr = FindInDomainList(pName,pDomainHead);
+ if (pNameAddr)
+ {
+ //
+ // the name matches, so add to the end of the ip address list
+ //
+ if (pNameAddr->CurrentLength < pNameAddr->MaxDomainAddrLength)
+ {
+ pIpAddr = pNameAddr->pIpList->IpAddr;
+
+ while (*pIpAddr != (ULONG)-1)
+ pIpAddr++;
+
+ *pIpAddr++ = IpAddress;
+ *pIpAddr = (ULONG)-1;
+ pNameAddr->CurrentLength += sizeof(ULONG);
+ }
+ else
+ {
+ //
+ // need to allocate more memory for for ip addresses
+ //
+ pIpAddr = CTEAllocInitMem(pNameAddr->MaxDomainAddrLength +
+ INITIAL_DOM_SIZE);
+
+ if (pIpAddr)
+ {
+ CTEMemCopy(pIpAddr,
+ pNameAddr->pIpList,
+ pNameAddr->MaxDomainAddrLength);
+
+ //
+ // Free the old chunk of memory and tack the new one on
+ // to the pNameaddr
+ //
+ CTEMemFree(pNameAddr->pIpList);
+ pNameAddr->pIpList = (tIPLIST *)pIpAddr;
+
+ pIpAddr = (PULONG)((PUCHAR)pIpAddr + pNameAddr->MaxDomainAddrLength);
+
+ //
+ // our last entry was -1: overwrite that one
+ //
+ pIpAddr--;
+
+ *pIpAddr++ = IpAddress;
+ *pIpAddr = (ULONG)-1;
+
+ //
+ // update the number of addresses in the list so far
+ //
+ pNameAddr->MaxDomainAddrLength += INITIAL_DOM_SIZE;
+ pNameAddr->CurrentLength += sizeof(ULONG);
+ pNameAddr->Verify = REMOTE_NAME;
+ }
+
+ }
+ }
+
+ }
+
+ //
+ // check if we found the name or we need to add a new name
+ //
+ if (!pNameAddr)
+ {
+ //
+ // create a new name for the domain list
+ //
+ pNameAddr = CTEAllocInitMem(sizeof(tNAMEADDR));
+ if (pNameAddr)
+ {
+ pIpAddr = CTEAllocInitMem(INITIAL_DOM_SIZE);
+ if (pIpAddr)
+ {
+ CTEMemCopy(pNameAddr->Name,pName,NETBIOS_NAME_SIZE);
+ pNameAddr->pIpList = (tIPLIST *)pIpAddr;
+ *pIpAddr++ = IpAddress;
+ *pIpAddr = (ULONG)-1;
+
+ pNameAddr->RefCount = 1;
+ pNameAddr->NameTypeState = NAMETYPE_INET_GROUP;
+ pNameAddr->MaxDomainAddrLength = INITIAL_DOM_SIZE;
+ pNameAddr->CurrentLength = 2*sizeof(ULONG);
+ pNameAddr->Verify = REMOTE_NAME;
+
+ InsertHeadList(pDomainHead,&pNameAddr->Linkage);
+ }
+ else
+ {
+ CTEMemFree(pNameAddr);
+ }
+
+ }
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+MakeNewListCurrent (
+ PLIST_ENTRY pTmpDomainList
+ )
+
+/*++
+
+Routine Description:
+
+ This function frees the old entries on the DomainList and hooks up the
+ new entries
+
+Arguments:
+
+ pTmpDomainList - list entry to the head of a new domain list
+
+Return Value:
+
+
+--*/
+
+
+{
+ CTELockHandle OldIrq;
+ tNAMEADDR *pNameAddr;
+ PLIST_ENTRY pEntry;
+ PLIST_ENTRY pHead;
+
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ if (!IsListEmpty(pTmpDomainList))
+ {
+ //
+ // free the old list elements
+ //
+ pHead = &DomainNames.DomainList;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ pEntry = pEntry->Flink;
+
+ RemoveEntryList(&pNameAddr->Linkage);
+ //
+ // initialize linkage so that if the nameaddr is being
+ // referenced now, when it does get freed in a subsequent
+ // call to NbtDereferenceName it will not
+ // remove it from any lists
+ //
+ InitializeListHead(&pNameAddr->Linkage);
+
+ //
+ // Since the name could be in use now we must dereference rather
+ // than just free it outright
+ //
+ NbtDereferenceName(pNameAddr);
+
+ }
+
+ DomainNames.DomainList.Flink = pTmpDomainList->Flink;
+ DomainNames.DomainList.Blink = pTmpDomainList->Blink;
+ pTmpDomainList->Flink->Blink = &DomainNames.DomainList;
+ pTmpDomainList->Blink->Flink = &DomainNames.DomainList;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+}
+
+//----------------------------------------------------------------------------
+
+char *
+LmExpandName (
+ OUT PUCHAR dest,
+ IN PUCHAR source,
+ IN UCHAR last
+ )
+
+/*++
+
+Routine Description:
+
+ This function expands an lmhosts entry into a full 16 byte NetBIOS
+ name. It is padded with blanks up to 15 bytes; the 16th byte is the
+ input parameter, last.
+
+ This function does not encode 1st level names to 2nd level names nor
+ vice-versa.
+
+ Both dest and source are NULL terminated strings.
+
+Arguments:
+
+ dest - sizeof(dest) must be NBT_NONCODED_NMSZ
+ source - the lmhosts entry
+ last - the 16th byte of the NetBIOS name
+
+Return Value:
+
+ dest.
+
+--*/
+
+
+{
+ char byte;
+ char *retval = dest;
+ char *src = source ;
+#ifndef VXD
+ WCHAR unicodebuf[NETBIOS_NAME_SIZE+1];
+ UNICODE_STRING unicode;
+ STRING tmp;
+#endif
+ NTSTATUS status;
+ PUCHAR limit;
+
+ CTEPagedCode();
+ //
+ // first, copy the source OEM string to the destination, pad it, and
+ // add the last character.
+ //
+ limit = dest + NETBIOS_NAME_SIZE - 1;
+
+ while ( (*source != '\0') && (dest < limit) )
+ {
+ *dest++ = *source++;
+ }
+
+ while(dest < limit)
+ {
+ *dest++ = ' ';
+ }
+
+ ASSERT(dest == (retval + NETBIOS_NAME_SIZE - 1));
+
+ *dest = '\0';
+ *(dest + 1) = '\0';
+ dest = retval;
+
+#ifndef VXD
+ //
+ // Now, convert to unicode then to ANSI to force the OEM -> ANSI munge.
+ // Then convert back to Unicode and uppercase the name. Finally convert
+ // back to OEM.
+ //
+ unicode.Length = 0;
+ unicode.MaximumLength = 2*(NETBIOS_NAME_SIZE+1);
+ unicode.Buffer = unicodebuf;
+
+ RtlInitString(&tmp, dest);
+
+ status = RtlOemStringToUnicodeString(&unicode, &tmp, FALSE);
+
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint((
+ "NBT LmExpandName: Oem -> Unicode failed, status %X\n",
+ status));
+ goto oldupcase;
+ }
+
+ status = RtlUnicodeStringToAnsiString(&tmp, &unicode, FALSE);
+
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint((
+ "NBT LmExpandName: Unicode -> Ansi failed, status %X\n",
+ status
+ ));
+ goto oldupcase;
+ }
+
+ status = RtlAnsiStringToUnicodeString(&unicode, &tmp, FALSE);
+
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint((
+ "NBT LmExpandName: Ansi -> Unicode failed, status %X\n",
+ status
+ ));
+ goto oldupcase;
+ }
+
+ status = RtlUpcaseUnicodeStringToOemString(&tmp, &unicode, FALSE);
+
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint((
+ "NBT LmExpandName: Unicode upcase -> Oem failed, status %X\n",
+ status
+ ));
+ goto oldupcase;
+ }
+
+ // write the last byte to "0x20" or "0x03" or whatever
+ // since we do not want it to go through the munge above.
+ //
+ dest[NETBIOS_NAME_SIZE-1] = last;
+ return(retval);
+
+#endif
+
+oldupcase:
+
+ for ( source = src ; dest < (retval + NETBIOS_NAME_SIZE - 1); dest++)
+ {
+ byte = *(source++);
+
+ if (!byte)
+ {
+ break;
+ }
+
+ // Don't use the c-runtime (nt c defn. included first)
+ // BUGBUG - What about extended characters etc.?
+ *dest = (byte >= 'a' && byte <= 'z') ? byte-'a' + 'A' : byte ;
+// *dest = islower(byte) ? toupper(byte) : byte;
+ }
+
+ for (; dest < retval + NETBIOS_NAME_SIZE - 1; dest++)
+ {
+ *dest = ' ';
+ }
+
+ ASSERT(dest == (retval + NETBIOS_NAME_SIZE - 1));
+
+ *dest = last;
+ *(dest + 1) = (char) NULL;
+
+ return(retval);
+} // LmExpandName
+
+//----------------------------------------------------------------------------
+
+unsigned long
+LmInclude(
+ IN PUCHAR file,
+ IN LM_PARSE_FUNCTION function,
+ IN PUCHAR argument OPTIONAL,
+ OUT BOOLEAN *NoFindName OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ LmInclude() is called to process a #INCLUDE directive in the lmhosts
+ file.
+
+Arguments:
+
+ file - the file to include
+ function - function to parse the included file
+ argument - optional second argument to the parse function
+ NoFindName - Are find names allowed for this address
+
+Return Value:
+
+ The return value from the parse function. This should be -1 if the
+ file could not be processed, or else some positive number.
+
+--*/
+
+
+{
+ int retval;
+ PUCHAR end;
+ NTSTATUS status;
+ PUCHAR path;
+
+ CTEPagedCode();
+ //
+ // unlike C, treat both variations of the #INCLUDE directive identically:
+ //
+ // #INCLUDE file
+ // #INCLUDE "file"
+ //
+ // If a leading '"' exists, skip over it.
+ //
+ if (*file == '"')
+ {
+
+ file++;
+
+ end = strchr(file, '"');
+
+ if (end)
+ {
+ *end = (UCHAR) NULL;
+ }
+ }
+
+ //
+ // check that the file to be included has been preloaded in the cache
+ // since we do not want to have the name query come right back to here
+ // to force another inclusion of the same remote file
+ //
+
+#ifdef VXD
+ return (*function)(file, argument, FALSE, NoFindName ) ;
+#else
+ status = LmGetFullPath(file, &path);
+
+ if (status != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("NBT: #INCLUDE \"%s\"\n", path));
+
+ retval = (*function) (path, argument, FALSE, NoFindName);
+
+ CTEMemFree(path);
+
+ return(retval);
+#endif
+} // LmInclude
+
+
+//----------------------------------------------------------------------------
+
+#ifndef VXD // Not used by VXD
+
+NTSTATUS
+LmGetFullPath (
+ IN PUCHAR target,
+ OUT PUCHAR *ppath
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the full path of the lmhosts file. This is done
+ by forming a string from the concatenation of the C strings
+ DatabasePath and the string, file.
+
+Arguments:
+
+ target - the name of the file. This can either be a full path name
+ or a mere file name.
+ path - a pointer to a UCHAR
+
+Return Value:
+
+ STATUS_SUCCESS if successful.
+
+Notes:
+
+ RtlMoveMemory() handles overlapped copies; RtlCopyMemory() doesn't.
+
+--*/
+
+{
+ ULONG FileNameType;
+ ULONG Len;
+ PUCHAR path;
+
+ CTEPagedCode();
+ //
+ // use a count to figure out what sort of string to build up
+ //
+ // 0 - local full path file name
+ // 1 - local file name only, no path
+ // 2 - remote file name
+ // 3 - \SystemRoot\ starting file name, or \DosDevices\UNC\...
+ //
+
+ // if the target begins with a '\', or contains a DOS drive letter,
+ // then assume that it specifies a full path. Otherwise, prepend the
+ // directory used to specify the lmhost file itself.
+ //
+ //
+ if (target[1] == ':')
+ {
+ FileNameType = 0;
+ }
+ else
+ if (strncmp(&target[1],"SystemRoot",10) == 0)
+ {
+ FileNameType = 3;
+ }
+ else
+ if (strncmp(&target[0],"\\DosDevices\\",12) == 0)
+ {
+ FileNameType = 3;
+ }
+ else
+ if (strncmp(target,"\\DosDevices\\UNC\\",sizeof("\\DosDevices\\UNC\\")-1) == 0)
+ {
+ FileNameType = 3;
+ }
+ else
+ {
+ FileNameType = 1;
+ }
+
+ //
+ // does the directory specify a remote file ?
+ //
+ // If so, it must be prefixed with "\\DosDevices\\UNC", and the double
+ // slashes of the UNC name eliminated.
+ //
+ //
+ if ((target[1] == '\\') && (target[0] == '\\'))
+ {
+ FileNameType = 2;
+ }
+
+ path = NULL;
+ switch (FileNameType)
+ {
+ case 0:
+ //
+ // Full file name, put \DosDevices on front of name
+ //
+ Len = sizeof("\\DosDevices\\") + strlen(target);
+ path = CTEAllocInitMem(Len);
+ if (path)
+ {
+ ULONG Length=sizeof("\\DosDevices\\"); // Took out -1
+
+ strncpy(path,"\\DosDevices\\",Length);
+ Nbtstrcat(path,target,Len);
+ }
+ break;
+
+
+ case 1:
+ //
+ // only the file name is present, with no path, so use the path
+ // specified for the lmhost file in the registry NbtConfig.PathLength
+ // includes the last backslash of the path.
+ //
+ //Len = sizeof("\\DosDevices\\") + NbtConfig.PathLength + strlen(target);
+ Len = NbtConfig.PathLength + strlen(target) +1;
+ path = CTEAllocInitMem(Len);
+ if (path)
+ {
+ //ULONG Length=sizeof("\\DosDevices") -1; // -1 not to count null
+
+ //strncpy(path,"\\DosDevices",Length);
+
+ strncpy(path,NbtConfig.pLmHosts,NbtConfig.PathLength);
+
+ Nbtstrcat(path,target,Len);
+ }
+
+ break;
+
+ case 2:
+ //
+ // Full file name, put \DosDevices\UNC on front of name and delete
+ // one of the two back slashes used for the remote name
+ //
+ Len = strlen(target);
+ path = CTEAllocInitMem(Len + sizeof("\\DosDevices\\UNC"));
+
+ if (path)
+ {
+ ULONG Length = sizeof("\\DosDevices\\UNC");
+
+ strncpy(path,"\\DosDevices\\UNC",Length);
+
+ // to delete the first \ from the two \\ on the front of the
+ // remote file name add one to target.
+ //
+ Nbtstrcat(path,target+1,Len+sizeof("\\DosDevices\\UNC"));
+ }
+ break;
+
+ case 3:
+ // the target is the full path
+ Len = strlen(target) + 1;
+ path = CTEAllocInitMem(Len);
+ if (path)
+ {
+ strncpy(path,target,Len);
+ }
+ break;
+
+
+ }
+
+ if (path)
+ {
+ *ppath = path;
+ return(STATUS_SUCCESS);
+ }
+ else
+ return(STATUS_UNSUCCESSFUL);
+} // LmGetFullPath
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NtCheckForIPAddr (
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID *pBuffer,
+ IN LONG Size,
+ IN PCTE_IRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This function is used to allow NBT to ping multiple IP addrs, by returning the buffer
+ passed into this routine with the IP list in it to lmhsvc.dll
+
+Arguments:
+
+Return Value:
+
+ STATUS_PENDING if the buffer is to be held on to, the normal case.
+
+Notes:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ NTSTATUS Locstatus;
+ CTELockHandle OldIrq;
+ tIPADDR_BUFFER_DNS *pIpAddrBuf;
+ PVOID pClientCompletion;
+ PVOID pClientContext;
+ tDGRAM_SEND_TRACKING *pTracker;
+ ULONG IpAddrsList[MAX_IPADDRS_PER_HOST+1];
+ PVOID Context;
+ BOOLEAN CompletingAnotherQuery = FALSE;
+
+
+ pIpAddrBuf = (tIPADDR_BUFFER_DNS *)pBuffer;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ CheckAddr.QueryIrp = pIrp;
+
+ status = STATUS_PENDING;
+
+ if (CheckAddr.ResolvingNow)
+ {
+
+ //
+ // if the client got tired of waiting for DNS, the WaitForDnsIrpCancel
+ // in ntisol.c will have cleared the Context value when cancelling the
+ // irp, so check for that here.
+ //
+ if (CheckAddr.Context)
+ {
+ Context = CheckAddr.Context;
+
+ CheckAddr.Context = NULL;
+
+ NTClearContextCancel( Context );
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+#if DBG
+ if (!pIpAddrBuf->Resolved) {
+ ASSERT(pIpAddrBuf->IpAddrsList[0] == 0);
+ }
+#endif
+ StartConnWithBestAddr(Context,
+ pIpAddrBuf->IpAddrsList,
+ (BOOLEAN)pIpAddrBuf->Resolved);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ }
+ else
+ {
+ KdPrint(("Nbt: NtDnsNameResolve: No Context!! *******\r\n"));
+ }
+
+ CheckAddr.ResolvingNow = FALSE;
+ //
+ // are there any more name query requests to process?
+ //
+ while (TRUE)
+ {
+ if (!IsListEmpty(&CheckAddr.ToResolve))
+ {
+ PLIST_ENTRY pEntry;
+
+ pEntry = RemoveHeadList(&CheckAddr.ToResolve);
+ Context = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ Locstatus = DoCheckAddr(Context);
+
+ //
+ // if it failed then complete the irp now
+ //
+ if (!NT_SUCCESS(Locstatus))
+ {
+ KdPrint(("NtDnsNameResolve: DoDnsResolve failed with %x\r\n",Locstatus));
+ pClientCompletion = ((NBT_WORK_ITEM_CONTEXT *)Context)->ClientCompletion;
+ pClientContext = ((NBT_WORK_ITEM_CONTEXT *)Context)->pClientContext;
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
+ //
+ // Clear the Cancel Routine now
+ //
+ (VOID)NTCancelCancelRoutine(((tDGRAM_SEND_TRACKING *)pClientContext)->pClientIrp);
+
+ DereferenceTracker(pTracker);
+
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ STATUS_BAD_NETWORK_PATH);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ }
+ else
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CompletingAnotherQuery = TRUE;
+ break;
+ }
+
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ }
+
+ //
+ // We are holding onto the Irp, so set the cancel routine.
+ if (!CompletingAnotherQuery)
+ {
+ status = NTCheckSetCancelRoutine(pIrp,CheckAddrIrpCancel,pDeviceContext);
+ if (!NT_SUCCESS(status))
+ {
+ // the irp got cancelled so complete it now
+ //
+ CheckAddr.QueryIrp = NULL;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ NTIoComplete(pIrp,status,0);
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = STATUS_PENDING;
+ }
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NtDnsNameResolve (
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID *pBuffer,
+ IN LONG Size,
+ IN PCTE_IRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This function is used to allow NBT to query DNS, by returning the buffer
+ passed into this routine with a name in it.
+
+Arguments:
+
+ target - the name of the file. This can either be a full path name
+ or a mere file name.
+ path - a pointer to a UCHAR
+
+Return Value:
+
+ STATUS_PENDING if the buffer is to be held on to, the normal case.
+
+Notes:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ NTSTATUS Locstatus;
+ CTELockHandle OldIrq;
+ tIPADDR_BUFFER_DNS *pIpAddrBuf;
+ PVOID pClientCompletion;
+ PVOID pClientContext;
+ tDGRAM_SEND_TRACKING *pTracker;
+ ULONG IpAddrsList[MAX_IPADDRS_PER_HOST+1];
+ PVOID Context;
+ BOOLEAN CompletingAnotherQuery = FALSE;
+
+
+ pIpAddrBuf = (tIPADDR_BUFFER_DNS *)pBuffer;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ DnsQueries.QueryIrp = pIrp;
+
+ status = STATUS_PENDING;
+
+ if (DnsQueries.ResolvingNow)
+ {
+
+ //
+ // if the client got tired of waiting for DNS, the WaitForDnsIrpCancel
+ // in ntisol.c will have cleared the Context value when cancelling the
+ // irp, so check for that here.
+ //
+ if (DnsQueries.Context)
+ {
+ Context = DnsQueries.Context;
+
+ DnsQueries.Context = NULL;
+
+ NTClearContextCancel( Context );
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ StartIpAddrToSrvName(Context,
+ pIpAddrBuf->IpAddrsList,
+ (BOOLEAN)pIpAddrBuf->Resolved);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ }
+ else
+ {
+ KdPrint(("Nbt: NtDnsNameResolve: No Context!! *******\r\n"));
+ }
+
+ DnsQueries.ResolvingNow = FALSE;
+ //
+ // are there any more name query requests to process?
+ //
+ while (TRUE)
+ {
+ if (!IsListEmpty(&DnsQueries.ToResolve))
+ {
+ PLIST_ENTRY pEntry;
+
+ pEntry = RemoveHeadList(&DnsQueries.ToResolve);
+ Context = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ Locstatus = DoDnsResolve(Context);
+
+ //
+ // if it failed then complete the irp now
+ //
+ if (!NT_SUCCESS(Locstatus))
+ {
+ KdPrint(("NtDnsNameResolve: DoDnsResolve failed with %x\r\n",Locstatus));
+ pClientCompletion = ((NBT_WORK_ITEM_CONTEXT *)Context)->ClientCompletion;
+ pClientContext = ((NBT_WORK_ITEM_CONTEXT *)Context)->pClientContext;
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
+ //
+ // Clear the Cancel Routine now
+ //
+ (VOID)NTCancelCancelRoutine(((tDGRAM_SEND_TRACKING *)pClientContext)->pClientIrp);
+
+ DereferenceTracker(pTracker);
+
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ STATUS_BAD_NETWORK_PATH);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ }
+ else
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CompletingAnotherQuery = TRUE;
+ break;
+ }
+
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ }
+
+ //
+ // We are holding onto the Irp, so set the cancel routine.
+ if (!CompletingAnotherQuery)
+ {
+ status = NTCheckSetCancelRoutine(pIrp,DnsIrpCancel,pDeviceContext);
+ if (!NT_SUCCESS(status))
+ {
+ // the irp got cancelled so complete it now
+ //
+ DnsQueries.QueryIrp = NULL;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ NTIoComplete(pIrp,status,0);
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = STATUS_PENDING;
+ }
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+DoDnsResolve (
+ IN NBT_WORK_ITEM_CONTEXT *Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to allow NBT to query DNS, by returning the buffer
+ passed into this routine with a name in it.
+
+Arguments:
+
+ target - the name of the file. This can either be a full path name
+ or a mere file name.
+ path - a pointer to a UCHAR
+
+Return Value:
+
+ STATUS_PENDING if the buffer is to be held on to , the normal case.
+
+Notes:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ tIPADDR_BUFFER_DNS *pIpAddrBuf;
+ PCTE_IRP pIrp;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tDGRAM_SEND_TRACKING *pClientTracker;
+ CTELockHandle OldIrq;
+ PCHAR pDestName;
+ ULONG NameLen;
+
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ Context->TimedOut = FALSE;
+ if (!DnsQueries.QueryIrp)
+ {
+ //
+ // the irp either never made it down here, or it was cancelled,
+ // so pretend the name query timed out.
+ //
+ KdPrint(("DoDnsResolve: QueryIrp is NULL, returning\r\n"));
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return(STATUS_BAD_NETWORK_PATH);
+ }
+ else
+ if (!DnsQueries.ResolvingNow)
+ {
+ DnsQueries.ResolvingNow = TRUE;
+ DnsQueries.Context = Context;
+ pIrp = DnsQueries.QueryIrp;
+
+ // this is the session setup tracker
+ pClientTracker = (tDGRAM_SEND_TRACKING *)Context->pClientContext;
+
+ // this is the name query tracker
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
+
+ //
+ // whenever dest. name is 16 bytes long (or smaller), we have no
+ // way of knowing if its a netbios name or a dns name, so we presume
+ // it's netbios name, go to wins, broadcast etc. and then come to dns
+ // In this case, the name query tracker will be setup, so be non-null
+ //
+ if (pTracker)
+ {
+ pDestName = pTracker->pNameAddr->Name;
+
+ //
+ // Ignore the 16th byte only if it is a non-DNS name character (we should be
+ // safe below 0x20). This will allow queries to DNS names which are exactly 16
+ // characters long.
+ //
+ if ((pDestName[NETBIOS_NAME_SIZE-1] <= 0x20 ) ||
+ (pDestName[NETBIOS_NAME_SIZE-1] >= 0x7f )) {
+ NameLen = NETBIOS_NAME_SIZE-1; // ignore 16th byte
+ } else {
+ NameLen = NETBIOS_NAME_SIZE;
+ }
+ }
+
+ //
+ // if the dest name is longer than 16 bytes, it's got to be dns name so
+ // we bypass wins etc. and come straight to dns. In this case, we didn't
+ // set up a name query tracker so it will be null. Use the session setup
+ // tracker (i.e. pClientTracker) to get the dest name
+ //
+ else
+ {
+ ASSERT(pClientTracker);
+
+ pDestName = pClientTracker->SendBuffer.pBuffer;
+
+ NameLen = pClientTracker->SendBuffer.Length;
+
+ //
+ // Ignore the 16th byte only if it is a non-DNS name character (we should be
+ // safe below 0x20). This will allow queries to DNS names which are exactly 16
+ // characters long.
+ //
+ if (NameLen == NETBIOS_NAME_SIZE) {
+ if ((pDestName[NETBIOS_NAME_SIZE-1] <= 0x20 ) ||
+ (pDestName[NETBIOS_NAME_SIZE-1] >= 0x7f )) {
+ NameLen = NETBIOS_NAME_SIZE-1; // ignore 16th byte
+ }
+ }
+ }
+
+
+ pIpAddrBuf = MmGetSystemAddressForMdl(pIrp->MdlAddress);
+
+ ASSERT(NameLen < 260);
+
+ //
+ // copy the name to the Irps return buffer for lmhsvc to resolve with
+ // a gethostbyname call
+ //
+ CTEMemCopy(pIpAddrBuf->pName,
+ pDestName,
+ NameLen);
+
+ pIpAddrBuf->pName[NameLen] = 0;
+
+ pIpAddrBuf->NameLen = NameLen;
+
+ //
+ // Since datagrams are buffered there is no client irp to get cancelled
+ // since the client's irp is returned immediately -so this check
+ // is only for connections being setup or QueryFindname or
+ // nodestatus, where we allow the irp to
+ // be cancelled.
+ //
+ status = STATUS_SUCCESS;
+ if (pClientTracker->pClientIrp)
+ {
+ //
+ // allow the client to cancel the name query Irp - no need to check
+ // if the client irp was already cancelled or not since the DNS query
+ // will complete and find no client request and stop.
+ //
+ status = NTCheckSetCancelRoutine(pClientTracker->pClientIrp,
+ WaitForDnsIrpCancel,NULL);
+ }
+
+ //
+ // pass the irp up to lmhsvc.dll to do a gethostbyname call to
+ // sockets
+ // The Irp will return to NtDnsNameResolve, above
+ //
+ if (NT_SUCCESS(status))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ NTIoComplete(DnsQueries.QueryIrp,STATUS_SUCCESS,0);
+ }
+ else
+ {
+ //
+ // We failed to set the cancel routine, so undo setting up the
+ // the DnsQueries structure.
+ //
+ KdPrint(("DoDnsResolve: CheckSet (submitting) failed with %x\r\n",status));
+ DnsQueries.ResolvingNow = FALSE;
+ DnsQueries.Context = NULL;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ }
+ else
+ {
+ //
+ // this is the session setup tracker
+ //
+ pClientTracker = (tDGRAM_SEND_TRACKING *)Context->pClientContext;
+ //
+ // Since datagrams are buffered there is no client irp to get cancelled
+ // since the client's irp is returned immediately -so this check
+ // is only for connections being setup, where we allow the irp to
+ // be cancelled.
+ //
+ status = STATUS_SUCCESS;
+ if (pClientTracker->pClientIrp)
+ {
+ //
+ // allow the client to cancel the name query Irp
+ //
+ status = NTCheckSetCancelRoutine(pClientTracker->pClientIrp,
+ WaitForDnsIrpCancel,NULL);
+ }
+ if (NT_SUCCESS(status))
+ {
+ // the irp is busy resolving another name, so wait for it to return
+ // down here again, mean while, Queue the name query
+ //
+ InsertTailList(&DnsQueries.ToResolve,&Context->Item.List);
+
+ }
+ else
+ {
+ KdPrint(("DoDnsResolve: CheckSet (queuing) failed with %x\r\n",status));
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ status = STATUS_PENDING;
+ }
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+DoCheckAddr (
+ IN NBT_WORK_ITEM_CONTEXT *Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to allow NBT to ping IP addrs, by returning the buffer
+ passed into this routine with the IP list in it.
+
+Arguments:
+
+Return Value:
+
+ STATUS_PENDING if the buffer is to be held on to , the normal case.
+
+Notes:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ tIPADDR_BUFFER_DNS *pIpAddrBuf;
+ PCTE_IRP pIrp;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tDGRAM_SEND_TRACKING *pClientTracker;
+ CTELockHandle OldIrq;
+ PCHAR pDestName;
+ ULONG NameLen;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ Context->TimedOut = FALSE;
+ if (!CheckAddr.QueryIrp)
+ {
+ //
+ // the irp either never made it down here, or it was cancelled,
+ // so pretend the name query timed out.
+ //
+ KdPrint(("DoCheckAddr: QueryIrp is NULL, returning\r\n"));
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return(STATUS_BAD_NETWORK_PATH);
+ }
+ else
+ if (!CheckAddr.ResolvingNow)
+ {
+ CheckAddr.ResolvingNow = TRUE;
+ CheckAddr.Context = Context;
+ pIrp = CheckAddr.QueryIrp;
+
+ // this is the session setup tracker
+ pClientTracker = (tDGRAM_SEND_TRACKING *)Context->pClientContext;
+
+ // this is the name query tracker
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
+
+ pIpAddrBuf = MmGetSystemAddressForMdl(pIrp->MdlAddress);
+
+ ASSERT(pTracker == NULL);
+
+ //
+ // copy the IP addrs for lmhsvc to ping...
+ //
+ CTEMemCopy(pIpAddrBuf->IpAddrsList,
+ pClientTracker->IpList,
+ (pClientTracker->NumAddrs+1) * sizeof(ULONG));
+
+ //
+ // Since datagrams are buffered there is no client irp to get cancelled
+ // since the client's irp is returned immediately -so this check
+ // is only for connections being setup or QueryFindname or
+ // nodestatus, where we allow the irp to
+ // be cancelled.
+ //
+ status = STATUS_SUCCESS;
+ if (pClientTracker->pClientIrp)
+ {
+ //
+ // allow the client to cancel the name query Irp - no need to check
+ // if the client irp was already cancelled or not since the DNS query
+ // will complete and find no client request and stop.
+ //
+ status = NTCheckSetCancelRoutine(pClientTracker->pClientIrp,
+ WaitForDnsIrpCancel,NULL);
+ }
+
+ //
+ // pass the irp up to lmhsvc.dll to do a gethostbyname call to
+ // sockets
+ // The Irp will return to NtDnsNameResolve, above
+ //
+ if (NT_SUCCESS(status))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ NTIoComplete(CheckAddr.QueryIrp,STATUS_SUCCESS,0);
+ }
+ else
+ {
+ //
+ // We failed to set the cancel routine, so undo setting up the
+ // the CheckAddr structure.
+ //
+ KdPrint(("DoCheckAddr: CheckSet (submitting) failed with %x\r\n",status));
+ CheckAddr.ResolvingNow = FALSE;
+ CheckAddr.Context = NULL;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ }
+ else
+ {
+ //
+ // this is the session setup tracker
+ //
+ pClientTracker = (tDGRAM_SEND_TRACKING *)Context->pClientContext;
+ //
+ // Since datagrams are buffered there is no client irp to get cancelled
+ // since the client's irp is returned immediately -so this check
+ // is only for connections being setup, where we allow the irp to
+ // be cancelled.
+ //
+ status = STATUS_SUCCESS;
+ if (pClientTracker->pClientIrp)
+ {
+ //
+ // allow the client to cancel the name query Irp
+ //
+ status = NTCheckSetCancelRoutine(pClientTracker->pClientIrp,
+ WaitForDnsIrpCancel,NULL);
+ }
+ if (NT_SUCCESS(status))
+ {
+ // the irp is busy resolving another name, so wait for it to return
+ // down here again, mean while, Queue the name query
+ //
+ InsertTailList(&CheckAddr.ToResolve,&Context->Item.List);
+
+ }
+ else
+ {
+ KdPrint(("DoCheckAddr: CheckSet (queuing) failed with %x\r\n",status));
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ status = STATUS_PENDING;
+ }
+
+ return(status);
+
+}
+#endif // !VXD
+
+//----------------------------------------------------------------------------
+ VOID
+StartIpAddrToSrvName(
+ IN NBT_WORK_ITEM_CONTEXT *Context,
+ IN ULONG *IpList,
+ IN BOOLEAN IpAddrResolved
+ )
+/*++
+
+Routine Description:
+
+ If the destination name is of the form 11.101.4.25 or is a dns name (i.e. of
+ the form ftp.microsoft.com) then we come to this function. In addition to
+ doing some house keeping, if the name did resolve then we also send out
+ a nodestatus request to find out the server name for that ipaddr
+
+Arguments:
+
+ Context - (NBT_WORK_ITEM_CONTEXT)
+ IpList - Array of ipaddrs if resolved (i.e. IpAddrResolved is TRUE)
+ IpAddrResolved - TRUE if ipaddr could be resolved, FALSE otherwise
+
+Return Value:
+
+ Nothing
+
+Notes:
+
+
+--*/
+
+{
+
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ PVOID pClientCompletion;
+ PVOID pClientContext;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tDGRAM_SEND_TRACKING *pClientTracker;
+ ULONG TdiAddressType;
+ CHAR szName[NETBIOS_NAME_SIZE];
+ ULONG IpAddrsList[MAX_IPADDRS_PER_HOST+1];
+ tDEVICECONTEXT *pDeviceContext;
+ int i;
+
+
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
+
+ pClientCompletion = ((NBT_WORK_ITEM_CONTEXT *)Context)->ClientCompletion;
+ pClientContext = ((NBT_WORK_ITEM_CONTEXT *)Context)->pClientContext;
+ pClientTracker = (tDGRAM_SEND_TRACKING *)pClientContext;
+
+ pDeviceContext = ((tDGRAM_SEND_TRACKING *)pClientContext)->pDeviceContext;
+ ASSERT(pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+
+ CTEMemFree(Context);
+
+ TdiAddressType = ((pTracker == NULL) &&
+ (pClientTracker->AddressType == TDI_ADDRESS_TYPE_NETBIOS_EX))
+ ? TDI_ADDRESS_TYPE_NETBIOS_EX
+ : TDI_ADDRESS_TYPE_NETBIOS;
+
+
+ // whether or not name resolved, we don't need this nameaddr anymore
+ // (if name resolved, then we do a node status to that addr and create
+ // a new nameaddr for the server name in ExtractServerName)
+ // pTracker is null if we went straight to dns (without wins etc)
+ if (pTracker)
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ NbtDereferenceName(pTracker->pNameAddr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+#ifndef VXD
+ (VOID)NTCancelCancelRoutine(((tDGRAM_SEND_TRACKING *)pClientContext)->pClientIrp);
+#endif
+
+ status = STATUS_BAD_NETWORK_PATH;
+
+ if (IpAddrResolved)
+ {
+ if (TdiAddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ for (i=0; i<MAX_IPADDRS_PER_HOST; i++)
+ {
+ IpAddrsList[i] = IpList[i];
+ if (IpAddrsList[i] == 0)
+ break;
+ }
+ IpAddrsList[MAX_IPADDRS_PER_HOST] = 0;
+
+ CTEZeroMemory(szName,NETBIOS_NAME_SIZE);
+ szName[0] = '*';
+
+ status = NbtSendNodeStatus(pDeviceContext,
+ szName,
+ NULL,
+ &IpAddrsList[0],
+ pClientContext,
+ pClientCompletion);
+ } else {
+ tNAMEADDR *pNameAddr;
+ PCHAR pRemoteName;
+ tCONNECTELE *pConnEle;
+
+ pConnEle = pClientTracker->Connect.pConnEle;
+ pRemoteName = pConnEle->RemoteName;
+
+ //
+ // add this server name to the remote hashtable
+ //
+ pNameAddr = NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('8'));
+ if (pNameAddr != NULL)
+ {
+ tNAMEADDR *pTableAddress;
+
+ CTEZeroMemory(pNameAddr,sizeof(tNAMEADDR));
+ InitializeListHead(&pNameAddr->Linkage);
+ CTEMemCopy(pNameAddr->Name,pRemoteName,NETBIOS_NAME_SIZE);
+ pNameAddr->Verify = REMOTE_NAME;
+ pNameAddr->RefCount = 1;
+ pNameAddr->NameTypeState = STATE_RESOLVED | NAMETYPE_UNIQUE;
+ pNameAddr->AdapterMask = (CTEULONGLONG)-1;
+ pNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
+ pNameAddr->IpAddress = IpList[0];
+
+ status = AddToHashTable(
+ NbtConfig.pRemoteHashTbl,
+ pNameAddr->Name,
+ NbtConfig.pScope,
+ 0,
+ 0,
+ pNameAddr,
+ &pTableAddress);
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("StartIpAddrToSrv...AddRecordToHashTable Status %lx\n",status));
+ } else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ status);
+ }
+ } else {
+ if (TdiAddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) {
+ tCONNECTELE *pConnEle;
+ pConnEle = pClientTracker->Connect.pConnEle;
+ pConnEle->RemoteNameDoesNotExistInDNS = TRUE;
+ }
+ }
+
+ // pTracker is null if we went straight to dns (without wins etc)
+ if (pTracker)
+ {
+ DereferenceTracker(pTracker);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ status);
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+StartConnWithBestAddr(
+ IN NBT_WORK_ITEM_CONTEXT *Context,
+ IN ULONG *IpList,
+ IN BOOLEAN IpAddrResolved
+ )
+/*++
+
+Routine Description:
+
+ If the destination name is of the form 11.101.4.25 or is a dns name (i.e. of
+ the form ftp.microsoft.com) then we come to this function. In addition to
+ doing some house keeping, if the name did resolve then we also send out
+ a nodestatus request to find out the server name for that ipaddr
+
+Arguments:
+
+ Context - (NBT_WORK_ITEM_CONTEXT)
+ IpList - Array of ipaddrs if resolved (i.e. IpAddrResolved is TRUE)
+ IpAddrResolved - TRUE if ipaddr could be resolved, FALSE otherwise
+
+Return Value:
+
+ Nothing
+
+Notes:
+
+
+--*/
+
+{
+
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ PVOID pClientCompletion;
+ PVOID pClientContext;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tDGRAM_SEND_TRACKING *pClientTracker;
+ ULONG TdiAddressType;
+ CHAR szName[NETBIOS_NAME_SIZE];
+ ULONG IpAddrsList[MAX_IPADDRS_PER_HOST+1];
+ tDEVICECONTEXT *pDeviceContext;
+ int i;
+
+ // IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Entered StartIpAddrToSrv\n"));
+
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
+
+ pClientCompletion = ((NBT_WORK_ITEM_CONTEXT *)Context)->ClientCompletion;
+ pClientContext = ((NBT_WORK_ITEM_CONTEXT *)Context)->pClientContext;
+ pClientTracker = (tDGRAM_SEND_TRACKING *)pClientContext;
+
+ pDeviceContext = ((tDGRAM_SEND_TRACKING *)pClientContext)->pDeviceContext;
+ ASSERT(pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+
+ CTEMemFree(Context);
+
+ // whether or not name resolved, we don't need this nameaddr anymore
+ // (if name resolved, then we do a node status to that addr and create
+ // a new nameaddr for the server name in ExtractServerName)
+ // pTracker is null if we went straight to dns (without wins etc)
+ if (pTracker)
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ NbtDereferenceName(pTracker->pNameAddr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+#ifndef VXD
+ (VOID)NTCancelCancelRoutine(((tDGRAM_SEND_TRACKING *)pClientContext)->pClientIrp);
+#endif
+
+ status = STATUS_BAD_NETWORK_PATH;
+
+ if (IpAddrResolved)
+ {
+ tNAMEADDR *pNameAddr;
+ PCHAR pRemoteName;
+ tCONNECTELE *pConnEle;
+
+ pConnEle = pClientTracker->Connect.pConnEle;
+ pRemoteName = pConnEle->RemoteName;
+
+ //
+ // add this server name to the remote hashtable
+ //
+ pNameAddr = NbtAllocMem(sizeof(tNAMEADDR),NBT_TAG('8'));
+ if (pNameAddr != NULL)
+ {
+ tNAMEADDR *pTableAddress;
+
+ CTEZeroMemory(pNameAddr,sizeof(tNAMEADDR));
+ InitializeListHead(&pNameAddr->Linkage);
+ CTEMemCopy(pNameAddr->Name,pRemoteName,NETBIOS_NAME_SIZE);
+ pNameAddr->Verify = REMOTE_NAME;
+ pNameAddr->RefCount = 1;
+ pNameAddr->NameTypeState = STATE_RESOLVED | NAMETYPE_UNIQUE;
+ pNameAddr->AdapterMask = (CTEULONGLONG)-1;
+ pNameAddr->TimeOutCount = NbtConfig.RemoteTimeoutCount;
+ pNameAddr->IpAddress = IpList[0];
+
+ status = AddToHashTable(
+ NbtConfig.pRemoteHashTbl,
+ pNameAddr->Name,
+ NbtConfig.pScope,
+ 0,
+ 0,
+ pNameAddr,
+ &pTableAddress);
+
+ // IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("StartIpAddrToSrv...AddRecordToHashTable Status %lx\n",status));
+ } else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ status);
+
+ // pTracker is null if we went straight to dns (without wins etc)
+ if (pTracker)
+ {
+ DereferenceTracker(pTracker);
+ }
+}
+
+//----------------------------------------------------------------------------
+ VOID
+ChangeStateInRemoteTable (
+ IN tIPLIST *pIpList,
+ OUT PVOID *pContext
+ )
+
+/*++
+
+Routine Description:
+
+ This function is not pagable - it grabs a spin lock and updates
+ pNameAddr. It removes the current context block from the LmHostQueries
+ structure in preparation for returning it to the client.
+
+Arguments:
+
+ Context -
+
+Return Value:
+
+ none
+
+--*/
+
+
+{
+ CTELockHandle OldIrq;
+ NBT_WORK_ITEM_CONTEXT *Context;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tNAMEADDR *pNameAddr;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (Context = LmHostQueries.Context)
+ {
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
+ pNameAddr = pTracker->pNameAddr;
+ LmHostQueries.Context = NULL;
+ NTClearContextCancel( Context );
+
+ pNameAddr->pIpList = pIpList;
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= NAMETYPE_INET_GROUP | STATE_RESOLVED;
+ *pContext = Context;
+
+ }
+ else
+ *pContext = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+PreloadEntry
+(
+ IN PUCHAR name,
+ IN unsigned long inaddr,
+ IN unsigned int NoFNR
+ )
+
+/*++
+
+Routine Description:
+
+ This function adds an lmhosts entry to nbt's name cache. For each
+ lmhosts entry, NSUFFIXES unique cache entries are created.
+
+ Even when some cache entries can't be created, this function doesn't
+ attempt to remove any that were successfully added to the cache.
+
+Arguments:
+
+ name - the unencoded NetBIOS name specified in lmhosts
+ inaddr - the ip address, in host byte order
+
+Return Value:
+
+ The number of new name cache entries created.
+
+--*/
+
+{
+ NTSTATUS status;
+ tNAMEADDR *pNameAddr;
+ LONG nentries;
+ LONG Len;
+ CHAR temp[NETBIOS_NAME_SIZE+1];
+ CTELockHandle OldIrq;
+ LONG NumberToAdd;
+
+ // if all 16 bytes are present then only add that name exactly as it
+ // is.
+ //
+ Len = strlen(name);
+ //
+ // if this string is exactly 16 characters long, do not expand
+ // into 0x00, 0x03,0x20 names. Just add the single name as it is.
+ //
+ if (Len == NETBIOS_NAME_SIZE)
+ {
+ NumberToAdd = 1;
+ }
+ else
+ {
+ NumberToAdd = NSUFFIXES;
+ }
+ for (nentries = 0; nentries < NumberToAdd; nentries++)
+ {
+
+//
+// don't allocate memory here: AddToHashTable allocates, and this memory leaks!
+//
+
+ // for names less than 16 bytes, expand out to 16 and put a 16th byte
+ // on according to the suffix array
+ //
+ if (Len != NETBIOS_NAME_SIZE)
+ {
+ LmExpandName(temp, name, Suffix[nentries]);
+ }
+ else
+ {
+ CTEMemCopy(temp,name,NETBIOS_NAME_SIZE);
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ // do not add the name if it is already in the hash table
+ status = AddNotFoundToHashTable(NbtConfig.pRemoteHashTbl,
+ temp,
+ NbtConfig.pScope,
+ inaddr,
+ NBT_UNIQUE,
+ &pNameAddr);
+
+ // if the name is already in the hash table, the status code is
+ // status pending. This could happen if the preloads are purged
+ // when one is still being referenced by another part of the code,
+ // and was therefore not deleted. We do not want to add the name
+ // twice, so we just change the ip address to agree with the preload
+ // value
+ //
+ if (status == STATUS_SUCCESS)
+ { //
+ // this prevents the name from being deleted by the Hash Timeout code
+ //
+ pNameAddr->RefCount = 2;
+ pNameAddr->NameTypeState |= PRELOADED | STATE_RESOLVED;
+ pNameAddr->NameTypeState &= ~STATE_CONFLICT;
+ pNameAddr->Ttl = 0xFFFFFFFF;
+ pNameAddr->Verify = REMOTE_NAME;
+ pNameAddr->AdapterMask = (CTEULONGLONG)-1;
+
+ }
+ else
+ pNameAddr->IpAddress = inaddr;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ if (Len == NETBIOS_NAME_SIZE)
+ {
+ return(STATUS_SUCCESS);
+ }
+
+ }
+
+ return(STATUS_SUCCESS);
+
+} // PreloadEntry
+//----------------------------------------------------------------------------
+ VOID
+RemovePreloads (
+ )
+
+/*++
+
+Routine Description:
+
+ This function removes preloaded entries from the remote hash table.
+ If it finds any of the preloaded entries are active with a ref count
+ above the base level of 2, then it returns true.
+
+Arguments:
+
+ none
+Return Value:
+
+ none
+
+--*/
+
+{
+ tNAMEADDR *pNameAddr;
+ PLIST_ENTRY pHead,pEntry;
+ CTELockHandle OldIrq;
+ tHASHTABLE *pHashTable;
+ BOOLEAN FoundActivePreload=FALSE;
+ LONG i;
+
+ //
+ // go through the remote table deleting names that have the PRELOAD
+ // bit set.
+ //
+ pHashTable = NbtConfig.pRemoteHashTbl;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ for (i=0;i < pHashTable->lNumBuckets ;i++ )
+ {
+ pHead = &pHashTable->Bucket[i];
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ pEntry = pEntry->Flink;
+ //
+ // Delete preloaded entries that are not in use by some other
+ // part of the code now. Note that preloaded entries start with
+ // a ref count of 2 so that the normal remote hashtimeout code
+ // will not delete them
+ //
+ if ((pNameAddr->NameTypeState & PRELOADED) &&
+ (pNameAddr->RefCount == 2))
+ {
+ //
+ // remove from the bucket that the name is in
+ //
+ RemoveEntryList(&pNameAddr->Linkage);
+ CTEMemFree((PVOID)pNameAddr);
+ }
+ }
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return;
+
+}
+
+//----------------------------------------------------------------------------
+ LONG
+PrimeCache(
+ IN PUCHAR path,
+ IN PUCHAR ignored,
+ IN BOOLEAN recurse,
+ OUT BOOLEAN *ignored2
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called to prime the cache with entries in the lmhosts
+ file that are marked as preload entries.
+
+
+Arguments:
+
+ path - a fully specified path to a lmhosts file
+ ignored - unused
+ recurse - TRUE if process #INCLUDE, FALSE otherwise
+
+Return Value:
+
+ Number of new cache entries that were added, or -1 if there was an
+ i/o error.
+
+--*/
+
+{
+ int nentries;
+ PUCHAR buffer;
+ PLM_FILE pfile;
+ NTSTATUS status;
+ int count, nwords;
+ unsigned long temp;
+ INCLUDE_STATE incstate;
+ PUCHAR token[MaxTokens];
+ ULONG inaddr;
+ LINE_CHARACTERISTICS current;
+ UCHAR Name[NETBIOS_NAME_SIZE+1];
+ ULONG IpAddr;
+ LIST_ENTRY TmpDomainList;
+ int domtoklen;
+
+ CTEPagedCode();
+
+ if (!NbtConfig.EnableLmHosts)
+ {
+ return(STATUS_SUCCESS);
+ }
+
+ InitializeListHead(&TmpDomainList);
+ //
+ // Check for infinitely recursive name lookup in a #INCLUDE.
+ //
+ if (LmpBreakRecursion(path, "") == TRUE)
+ {
+ return((unsigned long)0);
+ }
+
+ pfile = LmOpenFile(path);
+
+ if (!pfile)
+ {
+ return(-1);
+ }
+
+ nentries = 0;
+ incstate = MustInclude;
+ domtoklen = strlen(DOMAIN_TOKEN);
+
+ while (buffer = LmFgets(pfile, &count))
+ {
+
+#ifndef VXD
+ if ((MAX_PRELOAD - nentries) < 3)
+ {
+ break;
+ }
+#else
+ if ( nentries >= (MAX_PRELOAD - 3) )
+ {
+ break;
+ }
+#endif
+
+ nwords = MaxTokens;
+ current = LmpGetTokens(buffer, token, &nwords);
+
+ // if there is and error or no name on the line, then continue
+ // to the next line.
+ //
+ if ((current.l_category == ErrorLine) || (token[NbName] == NULL))
+ {
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("Nbt: Error line in Lmhost file\n"));
+ continue;
+ }
+
+ if (current.l_preload)
+ {
+ status = ConvertDottedDecimalToUlong(token[IpAddress],&inaddr);
+
+ if (NT_SUCCESS(status))
+ {
+ status = PreloadEntry( token[NbName],
+ inaddr,
+ (unsigned int)current.l_nofnr);
+ if (NT_SUCCESS(status))
+ {
+ nentries++;
+ }
+ }
+ }
+ switch ((ULONG)current.l_category)
+ {
+ case Domain:
+ if ((nwords - 1) < GroupName)
+ {
+ continue;
+ }
+
+ //
+ // and add '1C' on the end
+ //
+ LmExpandName(Name, token[GroupName]+ domtoklen, SPECIAL_GROUP_SUFFIX);
+
+ status = ConvertDottedDecimalToUlong(token[IpAddress],&IpAddr);
+ if (NT_SUCCESS(status))
+ {
+ AddToDomainList(Name,IpAddr,&TmpDomainList);
+ }
+
+ continue;
+
+ case Include:
+
+ if ((incstate == SkipInclude) || (nwords < 2))
+ {
+ continue;
+ }
+
+#ifdef VXD
+ //
+ // the buffer which we read into is reused for the next file: we
+ // need the contents when we get back: back it up!
+ // if we can't allocate memory, just skip this include
+ //
+ if ( !BackupCurrentData(pfile) )
+ {
+ continue;
+ }
+#endif
+
+ temp = LmInclude(token[1], PrimeCache, NULL, NULL);
+
+#ifdef VXD
+ //
+ // going back to previous file: restore the backed up data
+ //
+ RestoreOldData(pfile);
+#endif
+
+ if (temp != -1)
+ {
+
+ if (incstate == TryToInclude)
+ {
+ incstate = SkipInclude;
+ }
+ nentries += temp;
+ continue;
+ }
+
+ continue;
+
+ case BeginAlternate:
+ ASSERT(nwords == 1);
+ incstate = TryToInclude;
+ continue;
+
+ case EndAlternate:
+ ASSERT(nwords == 1);
+ incstate = MustInclude;
+ continue;
+
+ default:
+ continue;
+ }
+
+ }
+
+ status = LmCloseFile(pfile);
+ ASSERT(status == STATUS_SUCCESS);
+
+ //
+ // make this the new domain list
+ //
+ MakeNewListCurrent(&TmpDomainList);
+
+ ASSERT(nentries >= 0);
+ return(nentries);
+
+
+} // LmPrimeCache
+
+//----------------------------------------------------------------------------
+ VOID
+GetContext (
+ OUT PVOID *pContext
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called to get the context value to check if a name
+ query has been cancelled or not.
+
+Arguments:
+
+ Context -
+
+Return Value:
+
+ none
+
+--*/
+
+
+{
+ CTELockHandle OldIrq;
+ NBT_WORK_ITEM_CONTEXT *Context;
+
+ //
+ // remove the Context value and return it.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ if (Context = LmHostQueries.Context)
+ {
+#ifndef VXD
+ if ( NTCancelCancelRoutine(
+ ((tDGRAM_SEND_TRACKING *)(Context->pClientContext))->pClientIrp )
+ == STATUS_CANCELLED )
+ {
+ Context = NULL;
+ }
+ else
+#endif // VXD
+ {
+ LmHostQueries.Context = NULL;
+ }
+ }
+ *pContext = Context;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+ChangeStateOfName (
+ IN ULONG IpAddress,
+ IN NBT_WORK_ITEM_CONTEXT *Context,
+ OUT PVOID *pContext,
+ BOOLEAN Lmhosts
+ )
+
+/*++
+
+Routine Description:
+
+ This function changes the state of a name and nulls the Context
+ value in lmhostqueries.
+ When DNS processing calls this routine, the JointLock is already
+ held.
+
+Arguments:
+
+ Context -
+
+Return Value:
+
+ none
+
+--*/
+
+
+{
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ tDGRAM_SEND_TRACKING *pTracker;
+
+ if ( Context == NULL )
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ //
+ // change the state in the remote hash table
+ //
+ if (Lmhosts)
+ {
+ Context = LmHostQueries.Context;
+ LmHostQueries.Context = NULL;
+ }
+#ifndef VXD
+ else
+ {
+ Context = DnsQueries.Context;
+ DnsQueries.Context = NULL;
+ }
+ NTClearContextCancel( Context );
+#endif
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ if (Context)
+ {
+
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
+ pTracker->pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pTracker->pNameAddr->NameTypeState |= STATE_RESOLVED;
+
+ // convert broadcast addresses to zero since NBT interprets zero
+ // to be broadcast
+ //
+ if (IpAddress == (ULONG)-1)
+ {
+ IpAddress = 0;
+ }
+ pTracker->pNameAddr->IpAddress = IpAddress;
+
+ //
+ // put the name record into the hash table if it is not already
+ // there.
+ //
+ pTracker->pNameAddr->AdapterMask = (CTEULONGLONG)-1;
+ status = AddRecordToHashTable(pTracker->pNameAddr,NbtConfig.pScope);
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // this will free the memory, so do not access this after this
+ // point
+ //
+ NbtDereferenceName(pTracker->pNameAddr);
+ pTracker->pNameAddr = NULL;
+ }
+ *pContext = Context;
+ }
+ else
+ *pContext = NULL;
+}
+
+//----------------------------------------------------------------------------
+ VOID
+LmHostTimeout(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the timer code when the timer expires. It
+ marks all items in Lmhosts/Dns q as timed out and completes any that have
+ already timed out with status timeout.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ NBT_WORK_ITEM_CONTEXT *pWiContext;
+ LIST_ENTRY TmpHead;
+
+
+ //CTEQueueForNonDispProcessing(NULL,NULL,NULL,NonDispatchLmhostTimeout);
+
+ InitializeListHead(&TmpHead);
+ CTESpinLockAtDpc(&NbtConfig.JointLock);
+
+ //
+ // check the currently processing LMHOSTS entry
+ //
+ if (LmHostQueries.Context)
+ {
+ if (((NBT_WORK_ITEM_CONTEXT *)LmHostQueries.Context)->TimedOut)
+ {
+
+ pWiContext = (NBT_WORK_ITEM_CONTEXT *)LmHostQueries.Context;
+ LmHostQueries.Context = NULL;
+
+ //
+ // This asserts if the Irp has already been cancelled, which is bogus since
+ // it is possible to have the foll. swquence of events:
+ // 1. the Irp cancels into WaitForDnsIrpCancel; before it calls into DnsIrpCancelPaged,
+ // this routine is called. WaitForDnsIrpCancel waits at the JointLock.
+ // 2. so, here we try to clear the spinlock and discover that the Irp is cancelled, which is
+ // totally feasible.
+ //
+
+ // NTClearContextCancel( pWiContext );
+ (VOID)NTCancelCancelRoutine( ((tDGRAM_SEND_TRACKING *)(pWiContext->pClientContext))->pClientIrp );
+
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+ RemoveNameAndCompleteReq(pWiContext,STATUS_TIMEOUT);
+ CTESpinLockAtDpc(&NbtConfig.JointLock);
+ }
+ else
+ {
+
+ //
+ // restart the timer
+ //
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ ((NBT_WORK_ITEM_CONTEXT *)LmHostQueries.Context)->TimedOut = TRUE;
+
+ }
+ }
+#ifndef VXD
+ //
+ // check the currently processing DNS entry
+ //
+ if (DnsQueries.Context)
+ {
+ if (((NBT_WORK_ITEM_CONTEXT *)DnsQueries.Context)->TimedOut)
+ {
+
+ pWiContext = (NBT_WORK_ITEM_CONTEXT *)DnsQueries.Context;
+ DnsQueries.Context = NULL;
+ //
+ // This asserts if the Irp has already been cancelled, which is bogus since
+ // it is possible to have the foll. swquence of events:
+ // 1. the Irp cancels into WaitForDnsIrpCancel; before it calls into DnsIrpCancelPaged,
+ // this routine is called. WaitForDnsIrpCancel waits at the JointLock.
+ // 2. so, here we try to clear the spinlock and discover that the Irp is cancelled, which is
+ // totally feasible.
+ //
+
+ // NTClearContextCancel( pWiContext );
+ (VOID)NTCancelCancelRoutine( ((tDGRAM_SEND_TRACKING *)(pWiContext->pClientContext))->pClientIrp );
+
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+ RemoveNameAndCompleteReq(pWiContext,STATUS_TIMEOUT);
+ CTESpinLockAtDpc(&NbtConfig.JointLock);
+ }
+ else
+ {
+
+ //
+ // restart the timer
+ //
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ ((NBT_WORK_ITEM_CONTEXT *)DnsQueries.Context)->TimedOut = TRUE;
+
+ }
+ }
+ //
+ // go through the Lmhost and Dns queries finding any that have timed out
+ // and put them on a tmp list then complete them below.
+ //
+ TimeoutQEntries(&DnsQueries.ToResolve,&TmpHead,&pTimerQEntry->Flags);
+#endif
+ TimeoutQEntries(&LmHostQueries.ToResolve,&TmpHead,&pTimerQEntry->Flags);
+
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+
+ if (!IsListEmpty(&TmpHead))
+ {
+ pHead = &TmpHead;
+ pEntry = pHead->Flink;
+
+ while (pEntry != pHead)
+ {
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("Nbt: Timing Out Lmhost/Dns Entry\n"));
+
+ pWiContext = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
+ pEntry = pEntry->Flink;
+ RemoveEntryList(&pWiContext->Item.List);
+
+ RemoveNameAndCompleteReq(pWiContext,STATUS_TIMEOUT);
+ }
+ }
+
+ // null the timer if we are not going to restart it.
+ //
+ if (!(pTimerQEntry->Flags & TIMER_RESTART))
+ {
+ LmHostQueries.pTimer = NULL;
+ }
+}
+
+//----------------------------------------------------------------------------
+ VOID
+TimeoutQEntries(
+ IN PLIST_ENTRY pHeadList,
+ IN PLIST_ENTRY TmpHead,
+ OUT USHORT *pFlags
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to find timed out entries in the queue of
+ lmhost or dns name queries.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ PLIST_ENTRY pEntry;
+ NBT_WORK_ITEM_CONTEXT *pWiContext;
+
+ //
+ // Check the list of queued LMHOSTS entries
+ //
+ if (!IsListEmpty(pHeadList))
+ {
+ pEntry = pHeadList->Flink;
+
+ //
+ // restart the timer
+ //
+ *pFlags |= TIMER_RESTART;
+
+ while (pEntry != pHeadList)
+ {
+
+ pWiContext = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
+ pEntry = pEntry->Flink;
+
+ if (pWiContext->TimedOut)
+ {
+ //
+ // save on a temporary list and complete below
+ //
+ RemoveEntryList(&pWiContext->Item.List);
+ InsertTailList(TmpHead,&pWiContext->Item.List);
+ }
+ else
+ {
+ pWiContext->TimedOut = TRUE;
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+ VOID
+StartLmHostTimer(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN NBT_WORK_ITEM_CONTEXT *pContext
+ )
+
+/*++
+Routine Description
+
+ This routine handles setting up a timer to time the Lmhost entry.
+ The Joint Spin Lock is held when this routine is called
+
+Arguments:
+
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ NTSTATUS status;
+ tTIMERQENTRY *pTimerEntry;
+
+ pContext->TimedOut = FALSE;
+
+ //
+ // start the timer if it is not running
+ //
+ if (!LmHostQueries.pTimer)
+ {
+
+ status = StartTimer(
+ NbtConfig.LmHostsTimeout,
+ NULL, // context value
+ NULL, // context2 value
+ LmHostTimeout,
+ NULL,
+ LmHostTimeout,
+ 0,
+ &pTimerEntry);
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Start Timer to time Lmhost Qing for pConnEle= %X,\n",
+ pTracker->Connect.pConnEle));
+
+ if (NT_SUCCESS(status))
+ {
+ LmHostQueries.pTimer = pTimerEntry;
+
+ }
+ else
+ {
+ // we failed to get a timer, but that is not
+ // then end of the world. The lmhost query will just
+ // not timeout in 30 seconds. It may take longer if
+ // it tries to include a remove file on a dead machine.
+ //
+ LmHostQueries.pTimer = NULL;
+ }
+ }
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+LmHostQueueRequest(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PVOID pClientContext,
+ IN PVOID ClientCompletion,
+ IN PVOID CallBackRoutine,
+ IN PVOID pDeviceContext,
+ IN CTELockHandle OldIrq
+ )
+/*++
+
+Routine Description:
+
+ This routine exists so that LmHost requests will not take up more than
+ one executive worker thread. If a thread is busy performing an Lmhost
+ request, new requests are queued otherwise we could run out of worker
+ threads and lock up the system.
+
+ The Joint Spin Lock is held when this routine is called
+
+Arguments:
+ pTracker - the tracker block for context
+ CallbackRoutine - the routine for the Workerthread to call
+ pDeviceContext - dev context that initiated this
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status = STATUS_UNSUCCESSFUL ;
+ NBT_WORK_ITEM_CONTEXT *pContext;
+ NBT_WORK_ITEM_CONTEXT *pContext2;
+ tDGRAM_SEND_TRACKING *pTrackClient;
+ PCTE_IRP pIrp;
+ BOOLEAN OnList;
+
+
+ pContext = (NBT_WORK_ITEM_CONTEXT *)NbtAllocMem(sizeof(NBT_WORK_ITEM_CONTEXT),NBT_TAG('V'));
+ if (pContext)
+ {
+
+ pContext->pTracker = pTracker;
+ pContext->pClientContext = pClientContext;
+ pContext->ClientCompletion = ClientCompletion;
+
+ if (LmHostQueries.ResolvingNow)
+ {
+ // Lmhosts is busy resolving another name, so wait for it to return
+ // mean while, Queue the name query
+ //
+ InsertTailList(&LmHostQueries.ToResolve,&pContext->Item.List);
+ OnList = TRUE;
+
+ }
+ else
+ {
+ LmHostQueries.Context = pContext;
+ LmHostQueries.ResolvingNow = TRUE;
+ OnList = FALSE;
+
+#ifndef VXD
+ pContext2 = (NBT_WORK_ITEM_CONTEXT *)NbtAllocMem(sizeof(NBT_WORK_ITEM_CONTEXT),NBT_TAG('W'));
+
+ if (pContext2)
+ {
+ ExInitializeWorkItem(&pContext2->Item,CallBackRoutine,pContext2);
+ ExQueueWorkItem(&pContext2->Item,DelayedWorkQueue);
+ }
+#else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ VxdScheduleDelayedCall( pTracker, pClientContext, ClientCompletion, CallBackRoutine,pDeviceContext );
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+#endif
+ }
+
+ //
+ // To prevent this name query from languishing on the Lmhost Q when
+ // a #include on a dead machine is trying to be openned, start the
+ // connection setup timer
+ //
+ StartLmHostTimer(pTracker,pContext);
+
+ //
+ // this is the session setup tracker
+ //
+#ifndef VXD
+ pTrackClient = (tDGRAM_SEND_TRACKING *)pClientContext;
+ if (pIrp = pTrackClient->pClientIrp)
+ {
+ //
+ // allow the client to cancel the name query Irp
+ //
+ // but do not call NTSetCancel... since it takes need to run
+ // at non DPC level, and it calls the completion routine
+ // which takes the JointLock that we already have.
+
+ status = NTCheckSetCancelRoutine(pTrackClient->pClientIrp,
+ WaitForDnsIrpCancel,NULL);
+
+ //
+ // since the name query is cancelled do not let lmhost processing
+ // handle it.
+ //
+ if (status == STATUS_CANCELLED)
+ {
+ if (OnList)
+ {
+ RemoveEntryList(&pContext->Item.List);
+ }
+ else
+ {
+ LmHostQueries.Context = NULL;
+ //
+ // do not set resolving now to False since the work item
+ // has been queued to the worker thread
+ //
+ }
+
+ CTEMemFree(pContext);
+
+ }
+ return(status);
+ }
+#endif
+ status = STATUS_SUCCESS;
+ }
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+GetNameToFind(
+ OUT PUCHAR pName
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called to get the name to query from the LmHostQueries
+ list.
+
+Arguments:
+
+ Context -
+
+Return Value:
+
+ none
+
+--*/
+
+
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ NBT_WORK_ITEM_CONTEXT *Context;
+ PLIST_ENTRY pEntry;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ // if the context value has been cleared then that name query has been
+ // cancelled, so check for another one.
+ //
+ if (!(Context = LmHostQueries.Context))
+ {
+ //
+ // the current name query got canceled so see if there are any more
+ // to service
+ //
+ if (!IsListEmpty(&LmHostQueries.ToResolve))
+ {
+ pEntry = RemoveHeadList(&LmHostQueries.ToResolve);
+ Context = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
+ LmHostQueries.Context = Context;
+ }
+ else
+ {
+ //
+ // no more names to resolve, so clear the flag
+ //
+ LmHostQueries.ResolvingNow = FALSE;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return(STATUS_UNSUCCESSFUL);
+ }
+ }
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)Context)->pTracker;
+
+
+ CTEMemCopy(pName,pTracker->pNameAddr->Name,NETBIOS_NAME_SIZE);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return(STATUS_SUCCESS);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+ScanLmHostFile (
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the Executive Worker thread to scan the
+ LmHost file looking for a name. The name to query is on a list in
+ the DNSQueries structure.
+
+Arguments:
+
+ Context -
+
+Return Value:
+
+ none
+
+--*/
+
+
+{
+ NTSTATUS status;
+ LONG IpAddress;
+ ULONG IpAddrsList[2];
+ BOOLEAN bFound;
+ BOOLEAN bRecurse = TRUE;
+ PVOID pContext;
+ BOOLEAN DoingDnsResolve = FALSE;
+ UCHAR pName[NETBIOS_NAME_SIZE];
+ ULONG LoopCount;
+ tDEVICECONTEXT *pDeviceContext;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tDGRAM_SEND_TRACKING *pTracker0;
+
+ CTEPagedCode();
+
+
+#ifdef VXD
+ pDeviceContext = ((DELAYED_CALL_CONTEXT *)Context)->pDeviceContext;
+ ASSERT( pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
+#endif
+
+ //
+ // There is no useful info in Context, all the queued requests are on
+ // the ToResolve List, so free this memory now.
+ //
+ CTEMemFree(Context);
+
+ LoopCount = 0;
+ while (TRUE)
+ {
+
+ // get the next name on the linked list of LmHost name queries that
+ // are pending
+ //
+ pContext = NULL;
+ DoingDnsResolve = FALSE;
+ status = GetNameToFind(pName);
+ if ( !NT_SUCCESS(status))
+ return;
+ LOCATION(0x63);
+
+ LoopCount ++;
+
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("Nbt: Lmhosts pName = %15.15s<%X>,LoopCount=%X\n",
+ pName,pName[15],LoopCount));
+
+ status = STATUS_TIMEOUT;
+
+ //
+ // check if the name is in the lmhosts file or pass to Dns if
+ // DNS is enabled
+ //
+ IpAddress = 0;
+ if (NbtConfig.EnableLmHosts)
+ {
+ LOCATION(0x62);
+
+#ifdef VXD
+ //
+ // if for some reason PrimeCache failed at startup time
+ // then this is when we retry.
+ //
+ if (!CachePrimed)
+ {
+ if ( PrimeCache( NbtConfig.pLmHosts, NULL, TRUE, NULL) != -1 )
+ {
+ CachePrimed = TRUE ;
+ }
+ }
+#endif
+ IpAddress = LmGetIpAddr(NbtConfig.pLmHosts,
+ pName,
+ bRecurse,
+ &bFound);
+
+#ifdef VXD
+ //
+ // hmmm.. didn't find it in lmhosts: try hosts (if Dns is enabled)
+ //
+ if ( (IpAddress == (ULONG)0) && (NbtConfig.ResolveWithDns) )
+ {
+ IpAddress = LmGetIpAddr(NbtConfig.pHosts,
+ pName,
+ bRecurse,
+ &bFound);
+ }
+#endif
+ }
+
+
+ if (IpAddress == (ULONG)0)
+ {
+ // check if the name query has been cancelled
+ //
+ LOCATION(0x61);
+ GetContext(&pContext);
+ //
+ // for some reason we didn't find our context: maybe cancelled.
+ // Go back to the big while loop...
+ //
+ if (!pContext)
+ continue;
+
+ //
+ // see if the name is in the 11.101.4.26 format: if so, we got the
+ // ipaddr! Use that ipaddr to get the server name
+ //
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)pContext)->pTracker;
+
+ pTracker0 = (tDGRAM_SEND_TRACKING *)((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
+
+ if ( pTracker0->Flags & (REMOTE_ADAPTER_STAT_FLAG|SESSION_SETUP_FLAG|DGRAM_SEND_FLAG) )
+ {
+ IpAddress = Nbt_inet_addr(pTracker->pNameAddr->Name);
+ }
+ else
+ {
+ IpAddress = 0;
+ }
+ //
+ // yes, the name is the ipaddr: StartIpAddrToSrvName() starts
+ // the process of finding out server name for this ipaddr
+ //
+ if (IpAddress)
+ {
+ IpAddrsList[0] = IpAddress;
+ IpAddrsList[1] = 0;
+
+ //
+ // if this is in response to an adapter stat command (e.g.nbtstat -a) then
+ // don't try to find the server name (using remote adapter status!)
+ //
+ if (pTracker0->Flags & REMOTE_ADAPTER_STAT_FLAG)
+ {
+ //
+ // change the state to resolved if the name query is still pending
+ //
+ ChangeStateOfName(IpAddress,(NBT_WORK_ITEM_CONTEXT *)pContext,&pContext,TRUE);
+
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+
+ StartIpAddrToSrvName(pContext, IpAddrsList, TRUE);
+ //
+ // done with this name query: go back to the big while loop
+ //
+ continue;
+ }
+ }
+
+ //
+ //
+ // inet_addr failed. If DNS resolution is enabled, try DNS
+ else if (NbtConfig.ResolveWithDns)
+ {
+ status = DoDnsResolve(pContext);
+
+ if (NT_SUCCESS(status))
+ {
+ DoingDnsResolve = TRUE;
+ }
+ }
+ }
+
+ else // if (IpAddress != (ULONG)0)
+ {
+ //
+ // change the state to resolved if the name query is still pending
+ //
+ ChangeStateOfName(IpAddress,NULL,&pContext,TRUE);
+
+ status = STATUS_SUCCESS;
+ }
+
+ //
+ // if DNS gets involved, then we wait for that to complete before calling
+ // completion routine.
+ //
+ if (!DoingDnsResolve)
+ {
+ LOCATION(0x60);
+ RemoveNameAndCompleteReq((NBT_WORK_ITEM_CONTEXT *)pContext,
+ status);
+
+ }
+
+ }// of while(TRUE)
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+RemoveNameAndCompleteReq (
+ IN NBT_WORK_ITEM_CONTEXT *pContext,
+ IN NTSTATUS status
+ )
+
+/*++
+
+Routine Description:
+
+ This function removes the name, cleans up the tracker
+ and then completes the clients request.
+
+Arguments:
+
+ Context -
+
+Return Value:
+
+ none
+
+--*/
+
+
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ PVOID pClientContext;
+ PVOID pClientCompletion;
+ CTELockHandle OldIrq;
+
+ // if pContext is null the name query was cancelled during the
+ // time it took to go read the lmhosts file, so don't do this
+ // stuff
+ //
+ if (pContext)
+ {
+ pTracker = pContext->pTracker;
+ pClientCompletion = pContext->ClientCompletion;
+ pClientContext = pContext->pClientContext;
+
+ CTEMemFree(pContext);
+
+#ifndef VXD
+
+ //
+ // clear out the cancel routine if there is an irp involved
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ NTCancelCancelRoutine( ((tDGRAM_SEND_TRACKING *)(pClientContext))->pClientIrp );
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+#endif
+
+ // remove the name from the hash table, since it did not resolve
+ if ((status != STATUS_SUCCESS) && pTracker && pTracker->pNameAddr)
+ {
+ RemoveName(pTracker->pNameAddr);
+ }
+ // free the tracker and call the completion routine.
+ //
+ if (pTracker)
+ {
+ DereferenceTracker(pTracker);
+ }
+
+ if (pClientCompletion)
+ {
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ status);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+ VOID
+RemoveName (
+ IN tNAMEADDR *pNameAddr
+ )
+
+/*++
+
+Routine Description:
+
+ This function dereferences the pNameAddr and sets the state to Released
+ just incase the dereference does not delete the entry right away, due to
+ another outstanding reference against the name.
+
+Arguments:
+
+ Context -
+
+Return Value:
+
+ none
+
+--*/
+
+
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= STATE_RELEASED;
+ pNameAddr->pTracker = NULL;
+ NbtDereferenceName(pNameAddr);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+}
+//----------------------------------------------------------------------------
+//
+// Alternative to the c-runtime
+//
+char *
+#ifndef VXD // NT needs the CRTAPI1 modifier
+_CRTAPI1
+#endif
+strchr( const char * pch, int ch )
+{
+ while ( *pch != ch && *pch )
+ pch++ ;
+
+ if ( *pch == ch ) // Include '\0' in comparison
+ {
+ return (char *) pch ;
+ }
+
+ return NULL ;
+}
+//----------------------------------------------------------------------------
+//
+// Alternative to the c-runtime
+//
+#ifndef VXD
+PCHAR
+Nbtstrcat( PUCHAR pch, PUCHAR pCat, LONG Len )
+{
+ STRING StringIn;
+ STRING StringOut;
+
+ RtlInitAnsiString(&StringIn, pCat);
+ RtlInitAnsiString(&StringOut, pch);
+ StringOut.MaximumLength = (USHORT)Len;
+ //
+ // increment to include the null on the end of the string since
+ // we want that on the end of the final product
+ //
+ StringIn.Length++;
+ RtlAppendStringToString(&StringOut,&StringIn);
+
+
+ return(pch);
+}
+#else
+#define Nbtstrcat( a,b,c ) strcat( a,b )
+#endif
+
+
+
+
diff --git a/private/ntos/nbt/nbt/proxy.c b/private/ntos/nbt/nbt/proxy.c
new file mode 100644
index 000000000..f4ae4117b
--- /dev/null
+++ b/private/ntos/nbt/nbt/proxy.c
@@ -0,0 +1,282 @@
+//
+//
+// proxy.c
+//
+// This file contains the Proxy related functions that implement the Bnode
+// proxy functionality. This allows a Bnode to make use of a Name Service
+// transparently since the proxy code picks up the Bnode Query broadcasts directly
+// and either answers them directly or queries the NS and then answers them
+// later.
+// code
+
+#include "nbtprocs.h"
+
+VOID
+ProxyClientCompletion(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ );
+
+
+#ifdef PROXY_NODE
+//----------------------------------------------------------------------------
+ NTSTATUS
+RegOrQueryFromNet(
+ IN BOOL fReg,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNameSize,
+ IN PCHAR pNameInPkt,
+ IN PUCHAR pScope
+ )
+/*++
+
+Routine Description:
+
+ This function handles a name registration/name overwrite or a name
+ query that comes over the subnet. It checks the remote name table. If
+ the name is there, the function simply returns. If the name is not
+ there, the function calls QueryNameOnNet to add the name to the remote table
+ (in the resolving state) and to query the NS.
+
+ Note: If the name is there in the table, it may or may not have the same
+ address as the registration that we got or it may be of a different
+ type. Not doing anything for this case is ok as explained below.
+
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not - failure means no response to the net
+
+Called By:
+ QueryFromNet() in inbound.c, NameSrvHndlrNotOs() in hndlrs.c
+--*/
+{
+ tGENERALRR *pResrcRecord;
+ ULONG IpAddress;
+ BOOLEAN bGroupName;
+ CTELockHandle OldIrq;
+
+
+ //
+ // if we have heard a registration on the net, get the IP address
+ // and the type of registration (unique/group) from the packet.
+ //
+ // if we have heard a query, use default values for the above two
+ // fields
+ //
+ if (fReg)
+ {
+ // get the Ip address out of the Registration request
+ pResrcRecord = (tGENERALRR *)
+ ((ULONG)&pNameHdr->NameRR.NetBiosName[lNameSize]);
+ IpAddress = ntohl(pResrcRecord->IpAddress);
+ bGroupName = pResrcRecord->Flags & FL_GROUP;
+ }
+ else
+ {
+ IpAddress = 0;
+ bGroupName = NBT_UNIQUE; //default value
+ }
+ //
+ // The name is not there in the remote name table.
+ // Add it in the RESOLVING state and send a name query
+ // to the NS.
+ //
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ QueryNameOnNet(
+ pNameInPkt,
+ pScope,
+ IpAddress,
+ bGroupName,
+ NULL, //client context
+ ProxyClientCompletion,
+ PROXY,
+ NULL, //we want to add the name(pNameAddr = NULL)
+ pDeviceContext,
+ NULL, //no tracker block
+ &OldIrq
+ );
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+ProxyTimerComplFn (
+ IN PVOID pContext,
+ IN PVOID pContext2,
+ IN tTIMERQENTRY *pTimerQEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This function either deletes the name from the remote name table
+ if fReg is FALSE (i.e. the timer has expired on a name query
+ sent by the Proxy on behalf of a node doing a name query) or changes
+ the state to RESOLVED if fReg is TRUE (i.e. the timer has expired
+ on a name query sent on behalf of a node doing name registration)
+
+Arguments:
+ pfReg - indicates whether the timer expiry is for a name
+ query
+
+Return Value:
+
+ NTSTATUS - success or not - failure means no response to the net
+
+--*/
+{
+
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+ tNAMEADDR *pNameAddr;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ if (pTimerQEntry)
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (--pTimerQEntry->Retries)
+ {
+ // do send below...
+ }
+ else
+ {
+
+ if (pTracker->Flags & NBT_NAME_SERVER)
+ {
+ //
+ // Can't reach the name server, so try the backup
+ //
+ pTracker->Flags &= ~NBT_NAME_SERVER;
+ pTracker->Flags |= NBT_NAME_SERVER_BACKUP;
+
+ // set the retry count again
+ pTimerQEntry->Retries = NbtConfig.uNumRetries;
+
+ }
+ else
+ {
+
+
+ //
+ // If pContext2 is not 0, it means that this timer function was
+ // called by the proxy for a query which it sent on hearing a
+ // registration on the net. If pContext2 is 0, it means
+ // that the timer function was called by the proxy for a query
+ // which it sent on hearing a query on the net.
+ //
+
+ //
+ // Mark the entry as released. Do not dereference the name
+ // The entry will remain in the remote hash table. When the proxy
+ // code sees a query or registration for a released entry in the
+ // cache it does not query the name server. This cuts down on
+ // name server traffic. The released entries are removed from
+ // the cache at cache timer expiry (kept small).
+
+ //************************************
+
+ // Changed: Dereference the name because the name query timed
+ // out meaning that we did not contact WINS, therefore we
+ // do not know if the name is valid or not!
+ //
+
+ pNameAddr = pTracker->pNameAddr;
+ pTimerQEntry->ClientCompletion = NULL;
+
+ pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pNameAddr->NameTypeState |= STATE_RELEASED;
+
+ // remove the link from the name table to this timer block
+ CHECK_PTR(pNameAddr);
+ pNameAddr->pTimer = NULL;
+
+// NBT_PROXY_DBG(("ProxyTimerComplFn: State of name %16.16s(%X) changed to (%s)\n", pTracker->pNameAddr->Name, pTracker->pNameAddr->Name[15], "RELEASED"));
+
+
+ // Remove from the pending Queries list - and put into the hash
+ // table for 1 minute so we do not beat up on WINS if it is down
+ // or slow right now.
+ //
+ RemoveEntryList(&pNameAddr->Linkage);
+ InitializeListHead(&pNameAddr->Linkage);
+
+ status = AddRecordToHashTable(pNameAddr,NbtConfig.pScope);
+ if (!NT_SUCCESS(status))
+ {
+ NbtDereferenceName(pNameAddr);
+ }
+ else
+ {
+ pNameAddr->TimeOutCount = 1;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // return the tracker block to its queue
+ DereferenceTracker(pTracker);
+
+ return;
+ }
+ }
+
+ pTracker->RefCount++;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ status = UdpSendNSBcast(pTracker->pNameAddr,
+ NbtConfig.pScope,
+ pTracker,
+ NULL,NULL,NULL,
+ 0,0,
+ eNAME_QUERY,
+ TRUE);
+
+ DereferenceTracker(pTracker);
+ pTimerQEntry->Flags |= TIMER_RESTART;
+
+ }
+ else
+ {
+ // return the tracker block to its queue
+ DereferenceTrackerNoLock(pTracker);
+ }
+
+ return;
+}
+
+//----------------------------------------------------------------------------
+ VOID
+ProxyClientCompletion(
+ IN PVOID pContext,
+ IN NTSTATUS status
+ )
+
+/*++
+
+Routine Description:
+
+ This function does nothing since the proxy does not need to do anything
+ when a name query succeeds. The code in inbound.c does all that
+ is necessary - namely put the name in the name table.
+
+Arguments:
+
+Return Value:
+
+
+--*/
+{
+
+}
+
+#endif
diff --git a/private/ntos/nbt/nbt/sources.inc b/private/ntos/nbt/nbt/sources.inc
new file mode 100644
index 000000000..0327a43e3
--- /dev/null
+++ b/private/ntos/nbt/nbt/sources.inc
@@ -0,0 +1,65 @@
+!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:
+
+ Steve Wood 8/2/91
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nbt
+
+
+
+NTPROFILEINPUT=yes
+
+TARGETNAME=nbt
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+TARGETLIBS=
+
+INCLUDES=..\..\inc;..\..\..\inc;..\..\..\..\inc
+
+C_DEFINES=$(C_DEFINES) -DPROXY_NODE -D_NTDRIVER_ -DRASAUTODIAL -D_PNP_POWER -D_IO_DELETE_DEVICE_SUPPORTED
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES= $(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES= \
+ ..\hashtbl.c \
+ ..\hndlrs.c \
+ ..\inbound.c \
+ ..\name.c \
+ ..\namesrv.c \
+ ..\nbtutils.c \
+ ..\proxy.c \
+ ..\timer.c \
+ ..\udpsend.c \
+ ..\parse.c \
+ ..\init.c
+
+
+PRECOMPILED_INCLUDE=..\..\nbtprocs.h
+PRECOMPILED_PCH=nbtprocs.pch
+PRECOMPILED_OBJ=nbtprocs.obj
+ \ No newline at end of file
diff --git a/private/ntos/nbt/nbt/timer.c b/private/ntos/nbt/nbt/timer.c
new file mode 100644
index 000000000..ee6b315c1
--- /dev/null
+++ b/private/ntos/nbt/nbt/timer.c
@@ -0,0 +1,692 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Timer.c
+
+Abstract:
+
+
+ This file contains the code to implement timer functions.
+
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+#include "timer.h"
+
+// the timer Q
+tTIMERQ TimerQ;
+
+NTSTATUS
+DereferenceTimer(
+ IN tTIMERQENTRY *pTimerEntry
+ );
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+InitTimerQ(
+ IN int NumInQ)
+/*++
+
+Routine Description:
+
+ This routine calls InitQ to initialize the timer Q.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ return(InitQ(NumInQ,&TimerQ,sizeof(tTIMERQENTRY)));
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+InitQ(
+ IN int NumInQ,
+ IN tTIMERQ *pTimerQ,
+ IN USHORT uSize)
+/*++
+
+Routine Description:
+
+ This routine sets up the timer Q to have NumInQ entries to start with.
+ These are blocks allocated for timers so that ExAllocatePool does not
+ need to be done later.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ tTIMERQENTRY *pTimerEntry;
+
+ CTEInitLock(&pTimerQ->SpinLock);
+
+ InitializeListHead(&pTimerQ->ActiveHead);
+ InitializeListHead(&pTimerQ->FreeHead);
+
+ // allocate memory for the free list
+ while(NumInQ--)
+ {
+ pTimerEntry = (tTIMERQENTRY *)CTEAllocInitMem(uSize);
+ if (!pTimerEntry)
+ {
+ KdPrint(("Unable to allocate memory!! - for the timer Q\n"));
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ else
+ {
+ InsertHeadList(&pTimerQ->FreeHead,&pTimerEntry->Linkage);
+ }
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+StopTimerAndCallCompletion(
+ IN tTIMERQENTRY *pTimer,
+ IN NTSTATUS status,
+ IN CTELockHandle OldIrq
+ )
+/*++
+
+Routine Description:
+
+ This routine calls the routine to stop the timer and then calls the
+ completion routine if it hasn't been called yet.
+ This routine is called with the JointLock held.
+
+Arguments:
+
+Return Value:
+
+ there is no return value
+
+
+--*/
+{
+ NTSTATUS Locstatus;
+ COMPLETIONCLIENT pCompletion;
+ PVOID pContext;
+
+
+ if (pTimer)
+ {
+ Locstatus = StopTimer(pTimer,&pCompletion,&pContext);
+
+ // this will complete the irp(s) back to the clients
+ if (pCompletion)
+ {
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ CompleteClientReq(pCompletion,
+ pContext,
+ STATUS_TIMEOUT);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ }
+
+ }
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+InterlockedCallCompletion(
+ IN tTIMERQENTRY *pTimer,
+ IN NTSTATUS status
+ )
+/*++
+
+Routine Description:
+
+ This routine calls the completion routine if it hasn't been called
+ yet, by first getting the JointLock spin lock and then getting the
+ Completion routine ptr. If the ptr is null then the completion routine
+ has already been called. Holding the Spin lock interlocks this
+ with the timer expiry routine to prevent more than one call to the
+ completion routine.
+
+Arguments:
+
+Return Value:
+
+ there is no return value
+
+
+--*/
+{
+ CTELockHandle OldIrq;
+ COMPLETIONCLIENT pClientCompletion;
+
+ // to synch. with the the Timer completion routines, Null the client completion
+ // routine so it gets called just once, either from here or from the
+ // timer completion routine setup when the timer was started.(in namesrv.c)
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pClientCompletion = pTimer->ClientCompletion;
+ pTimer->ClientCompletion = NULL;
+
+
+ if (pClientCompletion)
+ {
+ // remove the link from the name table to this timer block
+ CHECK_PTR(((tNAMEADDR *)pTimer->pCacheEntry));
+ ((tNAMEADDR *)pTimer->pCacheEntry)->pTimer = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ (*pClientCompletion)(
+ pTimer->ClientContext,
+ status);
+ return(STATUS_SUCCESS);
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return(STATUS_UNSUCCESSFUL);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+GetEntry(
+ IN PLIST_ENTRY pQHead,
+ IN USHORT uSize,
+ OUT PLIST_ENTRY *ppEntry)
+/*++
+
+Routine Description:
+
+ This routine gets a free block from the Qhead passed in, and if the
+ list is empty it allocates another memory block for the queue.
+ NOTE: this function is called with the spin lock held on the Q structure
+ that contains Qhead.
+
+Arguments:
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+{
+ NTSTATUS status;
+ tTIMERQENTRY *pTimerEntry;
+
+ status = STATUS_SUCCESS;
+ if (!IsListEmpty(pQHead))
+ {
+ *ppEntry = RemoveHeadList(pQHead);
+
+ }
+ else
+ {
+ pTimerEntry = (tTIMERQENTRY *)CTEAllocInitMem(uSize);
+ if (!pTimerEntry)
+ {
+ KdPrint(("Unable to allocate memory!! - for the timer Q\n"));
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ // Note******:
+ // be sure to return a ptr to the Linkage ptr in the timerEntry
+ // structure, since the caller will use CONTAINING_RECORD to
+ // backup to the start of the record, since Linkage is not at
+ // the start of the record!!!
+ //
+ *ppEntry = &pTimerEntry->Linkage;
+
+ }
+
+ }
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+LockedStartTimer(
+ IN ULONG DeltaTime,
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PVOID CompletionRoutine,
+ IN PVOID ContextClient,
+ IN PVOID CompletionClient,
+ IN USHORT Retries,
+ IN tNAMEADDR *pNameAddr,
+ IN BOOLEAN CrossLink
+ )
+/*++
+
+Routine Description:
+
+ This routine starts a timer.
+
+Arguments:
+
+ The value passed in is in milliseconds - must be converted to 100ns
+ so multiply to 10,000
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+{
+ tTIMERQENTRY *pTimerEntry;
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ // get a free timer block
+ status = StartTimer(
+ DeltaTime,
+ pTracker,
+ NULL,
+ CompletionRoutine,
+ ContextClient,
+ CompletionClient,
+ Retries,
+ &pTimerEntry);
+
+ if (NT_SUCCESS(status))
+ {
+ // this boolean is passed in to determine which way
+ // to cross link the timerEntry and either the pNameaddr or
+ // the tracker, depending on who is calling this routine.
+ if (CrossLink)
+ {
+ // cross link the timer and the name address record
+ pTimerEntry->pCacheEntry = pNameAddr;
+ pNameAddr->pTimer = pTimerEntry;
+ }
+ else
+ {
+ pTracker->Connect.pNameAddr = pNameAddr;
+ pTracker->Connect.pTimer = pTimerEntry;
+ }
+
+
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return(status);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+StartTimer(
+ IN ULONG DeltaTime,
+ IN PVOID Context,
+ IN PVOID Context2,
+ IN PVOID CompletionRoutine,
+ IN PVOID ContextClient,
+ IN PVOID CompletionClient,
+ IN USHORT Retries,
+ OUT tTIMERQENTRY **ppTimerEntry)
+/*++
+
+Routine Description:
+
+ This routine starts a timer.
+
+Arguments:
+
+ The value passed in is in milliseconds - must be converted to 100ns
+ so multiply to 10,000
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+{
+ tTIMERQENTRY *pTimerEntry;
+ PLIST_ENTRY pEntry;
+ NTSTATUS status;
+
+ // get a free timer block
+ status = GetEntry(&TimerQ.FreeHead,sizeof(tTIMERQENTRY),&pEntry);
+ if (NT_SUCCESS(status))
+ {
+
+ pTimerEntry = CONTAINING_RECORD(pEntry,tTIMERQENTRY,Linkage);
+
+ pTimerEntry->DeltaTime = DeltaTime;
+ pTimerEntry->RefCount = 1;
+ //
+ // this is the context value and routine called when the timer expires,
+ // called by TimerExpiry below.
+ //
+ pTimerEntry->Context = Context;
+ pTimerEntry->Context2 = Context2;
+ pTimerEntry->CompletionRoutine = CompletionRoutine;
+ pTimerEntry->Flags = 0; // no flags
+
+ // now fill in the client's completion routines that ultimately get called
+ // after one or more timeouts...
+ pTimerEntry->ClientContext = (PVOID)ContextClient;
+ pTimerEntry->ClientCompletion = (COMPLETIONCLIENT)CompletionClient;
+ pTimerEntry->Retries = Retries;
+
+ CTEInitTimer(&pTimerEntry->VxdTimer);
+ CTEStartTimer(&pTimerEntry->VxdTimer,
+ pTimerEntry->DeltaTime,
+ (CTEEventRtn)TimerExpiry,
+ (PVOID)pTimerEntry);
+
+ // check if there is a ptr to return
+ if (ppTimerEntry)
+ {
+ *ppTimerEntry = pTimerEntry;
+ }
+
+ // put on list
+
+ InsertHeadList(&TimerQ.ActiveHead,pEntry);
+ }
+ else
+ {
+ KdPrint(("StartTimer: Unable to get a timer block\n"));
+ }
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+DereferenceTimer(
+ IN tTIMERQENTRY *pTimerEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine kills a timer if the reference count goes to zero. Called
+ with the TimerQ spin lock held.
+
+Arguments:
+
+
+Return Value:
+
+ returns the reference count after the decrement
+
+--*/
+{
+ NTSTATUS status;
+ COMPLETIONROUTINE CompletionRoutine;
+ PVOID Context;
+ PVOID Context2;
+
+ if (pTimerEntry->RefCount == 0)
+ {
+ // the expiry routine is not currently running so we can call the
+ // completion routine and remove the timer from the active timer Q
+
+ CompletionRoutine = (COMPLETIONROUTINE)pTimerEntry->CompletionRoutine;
+ Context = pTimerEntry->Context;
+ Context2 = pTimerEntry->Context2;
+
+ // move to the free list
+ RemoveEntryList(&pTimerEntry->Linkage);
+ InsertTailList(&TimerQ.FreeHead,&pTimerEntry->Linkage);
+
+ // release any tracker block hooked to the timer entry.. This could
+ // be modified to not call the completion routine if there was
+ // no context value... ie. for those timers that do not have anything
+ // to cleanup ...however, for now we require all completion routines
+ // to have a if (pTimerQEntry) if around the code so when it gets hit
+ // from this call it does not access any part of pTimerQEntry.
+ //
+ if (CompletionRoutine)
+ {
+ // call the completion routine so it can clean up its own buffers
+ // the routine that called this one will call the client's completion
+ // routine. A NULL timerEntry value indicates to the routine that
+ // cleanup should be done.
+ (VOID)(*CompletionRoutine)(
+ Context,
+ Context2,
+ NULL);
+
+ }
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ KdPrint(("Nbt:Unable to put timer back in free Q - RefCount = %X, %X\n",
+ pTimerEntry->RefCount,pTimerEntry));
+ }
+
+ return(status);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+StopTimer(
+ IN tTIMERQENTRY *pTimerEntry,
+ OUT COMPLETIONCLIENT *ppClientCompletion,
+ OUT PVOID *ppContext)
+/*++
+
+Routine Description:
+
+ This routine stops a timer. Must be called with the Joint lock held.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+
+ // null the client completion routine so that it can't be called again
+ // accidently
+ if (ppClientCompletion)
+ {
+
+ *ppClientCompletion = NULL;
+ }
+
+ // it is possible that the timer expiry routine has just run and the timer
+ // has not been restarted, so check the refcount, it will be zero if the
+ // timer was not restarted and 2 if the timer expiry is currently running.
+ if (pTimerEntry->RefCount == 1)
+ {
+ if (!(pTimerEntry->Flags & TIMER_NOT_STARTED))
+ CTEStopTimer( (CTETimer *)&pTimerEntry->VxdTimer );
+
+ status = STATUS_SUCCESS;
+
+ // this allows the caller to call the client's completion routine with
+ // the context value.
+ if (ppClientCompletion)
+ {
+ *ppClientCompletion = pTimerEntry->ClientCompletion;
+ }
+ if (ppContext)
+ {
+ *ppContext = pTimerEntry->ClientContext;
+ }
+ pTimerEntry->ClientCompletion = NULL;
+ pTimerEntry->RefCount = 0;
+
+ status = DereferenceTimer(pTimerEntry);
+
+
+ }
+ else
+ if (pTimerEntry->RefCount == 2)
+ {
+ // the timer expiry completion routines must set this routine to
+ // null with the spin lock held to synchronize with this stop timer
+ // routine. Likewise that routine checks this value too, to synchronize
+ // with this routine.
+ //
+ if (pTimerEntry->ClientCompletion)
+ {
+ // this allows the caller to call the client's completion routine with
+ // the context value.
+ if (ppClientCompletion)
+ {
+ *ppClientCompletion = pTimerEntry->ClientCompletion;
+ }
+ if (ppContext)
+ {
+ *ppContext = pTimerEntry->ClientContext;
+ }
+ // so that the timer completion routine cannot also call the client
+ // completion routine.
+ pTimerEntry->ClientCompletion = NULL;
+
+ }
+
+ // signal the TimerExpiry routine that the timer has been cancelled
+ //
+ pTimerEntry->RefCount++;
+ status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ return(status);
+
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+TimerExpiry(
+#ifndef VXD
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArg1,
+ IN PVOID SystemArg2
+#else
+ IN CTEEvent * pCTEEvent,
+ IN PVOID DeferredContext
+#endif
+ )
+/*++
+
+Routine Description:
+
+ This routine is the timer expiry completion routine. It is called by the
+ kernel when the timer expires.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ tTIMERQENTRY *pTimerEntry;
+ CTELockHandle OldIrq1;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ // get the timer Q list entry from the context passed in
+ pTimerEntry = (tTIMERQENTRY *)DeferredContext;
+
+
+ if (pTimerEntry->RefCount == 0)
+ {
+ // the timer has been cancelled already!
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return;
+ }
+
+ // increment the reference count because we are handling a timer completion
+ // now
+ pTimerEntry->RefCount++;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // call the completion routine passing the context value
+ pTimerEntry->Flags &= ~TIMER_RESTART; // incase the clients wants to restart the timer
+ (*(COMPLETIONROUTINE)pTimerEntry->CompletionRoutine)(
+ pTimerEntry->Context,
+ pTimerEntry->Context2,
+ pTimerEntry);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ pTimerEntry->RefCount--;
+ if (pTimerEntry->Flags & TIMER_RESTART)
+ {
+ if (pTimerEntry->RefCount == 2)
+ {
+ // the timer was stopped during the expiry processing, so call the
+ // deference routine
+ //
+ pTimerEntry->RefCount = 0;
+ DereferenceTimer(pTimerEntry);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ return;
+ }
+ else
+ {
+
+ CTEStartTimer(&pTimerEntry->VxdTimer,
+ pTimerEntry->DeltaTime,
+ (CTEEventRtn)TimerExpiry,
+ (PVOID)pTimerEntry);
+
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return;
+
+ }
+ else
+ {
+
+ // move to the free list after setting the reference count to zero
+ // since this tierm block is no longer active.
+ //
+ pTimerEntry->RefCount = 0;
+ RemoveEntryList(&pTimerEntry->Linkage);
+ InsertTailList(&TimerQ.FreeHead,&pTimerEntry->Linkage);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ }
+
+}
+
diff --git a/private/ntos/nbt/nbt/udpsend.c b/private/ntos/nbt/nbt/udpsend.c
new file mode 100644
index 000000000..b30208b50
--- /dev/null
+++ b/private/ntos/nbt/nbt/udpsend.c
@@ -0,0 +1,1742 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Udpsend.c
+
+Abstract:
+
+
+ This file handles building udp(and Tcp) requests, formated to the Tdi specification
+ to pass to Tdiout. Tdiout formats the request in an Os specific manner and
+ passes it on to the transport.
+
+ This file handles name service type functions such as query name or
+ register name, datagram sends. It also handles building Tcp packets.
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+
+#include "nbtprocs.h" // procedure headings
+
+
+VOID
+SessionRespDone(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo);
+VOID
+NsDgramSendCompleted(
+ PVOID pContext,
+ NTSTATUS status,
+ ULONG lInfo
+ );
+VOID
+NDgramSendCompleted(
+ PVOID pContext,
+ NTSTATUS status,
+ ULONG lInfo
+ );
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+UdpSendNSBcast(
+ IN tNAMEADDR *pNameAddr,
+ IN PCHAR pScope,
+ IN tDGRAM_SEND_TRACKING *pSentList,
+ IN PVOID pCompletionRoutine,
+ IN PVOID pClientContext,
+ IN PVOID pClientCompletion,
+ IN ULONG Retries,
+ IN ULONG Timeout,
+ IN enum eNSTYPE eNsType,
+ IN BOOL SendFlag
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a name registration or a name query
+ as a broadcast on the subnet or directed to the name server.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ NTSTATUS status;
+ tNAMEHDR *pNameHdr;
+ ULONG uLength;
+ tDEVICECONTEXT *pDeviceContext;
+ CTELockHandle OldIrq;
+ ULONG UNALIGNED *pHdrIpAddress;
+ ULONG IpAddress;
+ USHORT Port;
+ USHORT NameType;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tTIMERQENTRY *pTimerQEntry;
+ PFILE_OBJECT pFileObject;
+
+
+ if (pNameAddr->NameTypeState & (NAMETYPE_GROUP | NAMETYPE_INET_GROUP))
+ {
+ NameType = NBT_GROUP;
+ }
+ else
+ NameType = NBT_UNIQUE;
+
+ // build the correct type of pdu depending on the request type
+
+ status = GetTracker(&pTracker);
+ if (!NT_SUCCESS(status))
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pHdrIpAddress = (ULONG UNALIGNED *)CreatePdu(
+ pNameAddr->Name,
+ pScope,
+ 0L, // we don't know the IP address yet
+ NameType,
+ eNsType,
+ (PVOID)&pNameHdr,
+ &uLength,
+ pSentList);
+
+ if (pHdrIpAddress)
+ {
+ //
+ // change the dgram header for name refreshes
+ //
+ if (eNsType == eNAME_REFRESH)
+ {
+ pNameHdr->OpCodeFlags = NbtConfig.OpRefresh;
+ }
+ else
+ if ( (eNsType == eNAME_QUERY)
+#ifdef VXD
+ || (eNsType == eDNS_NAME_QUERY)
+#endif
+ )
+ {
+ pHdrIpAddress = NULL;
+ }
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Failed to Create Pdu to send to WINS PduType= %X\n",
+ eNsType));
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+
+ // fill in the Datagram hdr info in the tracker structure.
+ // There is never a client buffer to send.
+ //
+ // Set the fields here instead of after the timer is started
+ // since they may be accessed by the Timer completion function
+ //
+ pTracker->SendBuffer.pDgramHdr = pNameHdr;
+ pTracker->SendBuffer.HdrLength = uLength;
+ pTracker->SendBuffer.pBuffer = NULL;
+ pTracker->SendBuffer.Length = 0;
+ pTracker->pNameAddr = pNameAddr;
+
+ pTracker->pDeviceContext = pSentList->pDeviceContext;
+
+ pSentList->pNameAddr = pNameAddr;
+ pSentList->TransactionId = pNameHdr->TransactId; // save for response checks.
+
+
+ pTracker->pHdrIpAddress = pHdrIpAddress;
+
+ // start the timer now...We didn't start it before because it could
+ // have expired during the dgram setup, perhaps before the Tracker was
+ // fully setup.
+ //
+ if (Timeout)
+ {
+ status = StartTimer(
+ Timeout,
+ (PVOID)pSentList, // context value
+ NULL,
+ pCompletionRoutine,
+ pClientContext,
+ pClientCompletion,
+ (USHORT)Retries,
+ &pTimerQEntry
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ // we need to differentiate the timer failing versus lack
+ // of resources
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ CTEMemFree(pNameHdr);
+
+ FreeTracker(pTracker,RELINK_TRACKER);
+
+ return(STATUS_INVALID_PARAMETER_6);
+ }
+ //
+ // Cross link the nameaddr and the timer so we can stop the timer
+ // when the name query response occurs
+ //
+ pTimerQEntry->pCacheEntry = pNameAddr;
+ pNameAddr->pTimer = pTimerQEntry;
+ }
+
+ pDeviceContext = pSentList->pDeviceContext;
+
+ //
+ // Check the Flag value in the tracker and see if we should do a broadcast
+ // or a directed send to the name server
+ //
+ if (pSentList->Flags & NBT_BROADCAST)
+ {
+ //
+ // set the broadcast bit in the header to be ON since this may be
+ // an M or MS node that is changing to broadcast from directed sends.
+ //
+ ((PUCHAR)pTracker->SendBuffer.pDgramHdr)[3] |= FL_BROADCAST_BYTE;
+
+ Port = NBT_NAMESERVICE_UDP_PORT;
+
+ IpAddress = pDeviceContext->BroadcastAddress;
+ }
+ else
+ {
+ //
+ // turn off the broadcast bit in the header since this may be
+ // an M or MS node that is changing to directed sends from broadcasts.
+ //
+ ((PUCHAR)pTracker->SendBuffer.pDgramHdr)[3] &= ~FL_BROADCAST_BYTE;
+
+ // check for a zero first byte in the name passed to the name server
+ ASSERT(((PUCHAR)pTracker->SendBuffer.pDgramHdr)[12]);
+
+ //
+ // for Multihomed hosts, UNIQUE name registrations use a special new
+ // code (0x0F) to tell the name server this is a multihomed name that
+ // will have several ip addresses
+ //
+ if (NbtConfig.MultiHomed &&
+ ((eNsType == eNAME_REGISTRATION) && (NameType == NBT_UNIQUE)))
+ {
+ // if it is a multihomed host, then use a new special registration
+ // opcode (0xF)
+ //
+ ((PUCHAR)pTracker->SendBuffer.pDgramHdr)[2] |= OP_REGISTER_MULTI;
+
+ }
+
+ Port = NbtConfig.NameServerPort;
+
+ // name srvr, backup name srvr, dns srvr, backup dnr srvr:which one?
+
+ if (pSentList->Flags & NBT_NAME_SERVER)
+ {
+ IpAddress = pDeviceContext->lNameServerAddress;
+ }
+ else
+#ifndef VXD
+ {
+ IpAddress = pDeviceContext->lBackupServer;
+ }
+#else
+ if (pSentList->Flags & NBT_NAME_SERVER_BACKUP)
+ {
+ IpAddress = pDeviceContext->lBackupServer;
+ }
+ else
+ if (pSentList->Flags & NBT_DNS_SERVER)
+ {
+ IpAddress = pDeviceContext->lDnsServerAddress;
+ Port = NbtConfig.DnsServerPort;
+ }
+ else // ----- if (pSentList->Flags & NBT_DNS_SERVER_BACKUP) ----
+ {
+ IpAddress = pDeviceContext->lDnsBackupServer;
+ Port = NbtConfig.DnsServerPort;
+ }
+#endif
+
+
+ //
+ // is it is a send to WINS on this machine
+ //
+ if (pNameHdr->AnCount == (UCHAR)WINS_SIGNATURE)
+ {
+ IpAddress = pDeviceContext->IpAddress;
+ }
+ }
+
+ ASSERT(pSentList->Flags);
+
+ // each adapter has a different source Ip address for registrations
+ // - pHdrIpAddress is NULL for queries...
+ if (pHdrIpAddress)
+ {
+ *pHdrIpAddress = htonl(pDeviceContext->IpAddress);
+ }
+
+ //
+ // in the event that DHCP has just removed the IP address, use a null
+ // FileObject to signal UdpSendDatagram not to do the send
+ //
+ if (
+ (pDeviceContext->IpAddress == 0)
+ || ( !SendFlag )
+ )
+ {
+ pFileObject = NULL;
+ }
+ else
+ {
+ //
+ // If the device has been destroyed, dont send anything.
+ //
+ if (InterlockedExchangeAdd(&pDeviceContext->IsDestroyed, 0) != 0) {
+ pFileObject = NULL;
+ } else {
+ pFileObject = pDeviceContext->pNameServerFileObject;
+ }
+
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = UdpSendDatagram(
+ pTracker,
+ IpAddress,
+ pFileObject,
+ NDgramSendCompleted,
+ pTracker,
+ Port,
+ NBT_NAME_SERVICE
+ );
+
+ return(status);
+}
+//----------------------------------------------------------------------------
+ PVOID
+CreatePdu(
+ IN PCHAR pName,
+ IN PCHAR pScope,
+ IN ULONG IpAddress,
+ IN USHORT NameType,
+ IN enum eNSTYPE eNsType,
+ OUT PVOID *pHdrs,
+ OUT PULONG pLength,
+ IN tDGRAM_SEND_TRACKING *pTracker
+ )
+/*++
+
+Routine Description:
+
+ This routine builds a registration pdu
+
+Arguments:
+
+
+Return Value:
+
+ PULONG - a ptr to the ip address in the pdu so it can be filled in later
+
+--*/
+{
+ tNAMEHDR *pNameHdr;
+ ULONG uLength;
+ ULONG uScopeSize;
+ tGENERALRR *pGeneral;
+ CTELockHandle OldIrq;
+
+
+#ifdef VXD
+ if ( (eNsType == eDNS_NAME_QUERY) || (eNsType == eDIRECT_DNS_NAME_QUERY) )
+ {
+ uScopeSize = domnamelen(pTracker->pchDomainName) + 1; // +1 for len byte
+ if (uScopeSize > 1)
+ {
+ uScopeSize++; // for the null byte
+ }
+ }
+ else
+#endif
+ uScopeSize = strlen(pScope) +1; // +1 for null too
+
+
+ // size is size of the namehdr structure -1 for the NetbiosName[1]
+ // + the 32 bytes for the half ascii name +
+ // scope + size of the General RR structure
+ uLength = sizeof(tNAMEHDR) - 1
+ + (NETBIOS_NAME_SIZE << 1)
+ + uScopeSize;
+
+ if (eNsType == eNAME_QUERY)
+ {
+ uLength = uLength + sizeof(ULONG);
+ }
+#ifdef VXD
+ // there is no half-ascii conversion in DNS. we added 32 bytes above, but
+ // we need only 16. so, subtract 16.
+ else if (eNsType == eDNS_NAME_QUERY)
+ {
+ uLength = uLength - NETBIOS_NAME_SIZE + sizeof(ULONG);
+ }
+ // This is a "raw" DNS name query. Substitute raw string length of pName
+ // for NETBIOS_NAME_SIZE.
+ else if (eNsType == eDIRECT_DNS_NAME_QUERY)
+ {
+ uLength = uLength - (NETBIOS_NAME_SIZE << 1) + sizeof(ULONG) + strlen(pName) + 1;
+ }
+#endif
+ else
+ {
+ uLength += sizeof(tGENERALRR);
+ }
+
+ // Note that this memory must be deallocated when the send completes in
+ // tdiout.DgramSendCompletion
+ pNameHdr = NbtAllocMem((USHORT)uLength ,NBT_TAG('X'));
+
+ if (!pNameHdr)
+ {
+ return(NULL);
+ }
+
+ CTEZeroMemory((PVOID)pNameHdr,uLength);
+
+ //
+ // for resends of the same name query or name registration, do not increment
+ // the transaction id
+ //
+ if (pTracker->TransactionId)
+ {
+ pNameHdr->TransactId = pTracker->TransactionId;
+ }
+ else
+ {
+ pNameHdr->TransactId = htons(GetTransactId());
+ }
+
+ pNameHdr->QdCount = 1;
+ pNameHdr->AnCount = 0;
+ pNameHdr->NsCount = 0;
+
+
+#ifdef VXD
+ if ((eNsType != eDNS_NAME_QUERY)&&(eNsType != eDIRECT_DNS_NAME_QUERY))
+ {
+#endif
+ // Convert the name to half ascii and copy!! ... adding the scope too
+ pGeneral = (tGENERALRR *)ConvertToHalfAscii(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ pName,
+ pScope,
+ uScopeSize);
+
+ pGeneral->Question.QuestionTypeClass = htonl(QUEST_NBINTERNET);
+#ifdef VXD
+ }
+#endif
+
+ *pHdrs = (PVOID)pNameHdr;
+ *pLength = uLength;
+
+ switch (eNsType)
+
+ {
+
+#ifdef VXD
+ case eDNS_NAME_QUERY:
+ case eDIRECT_DNS_NAME_QUERY:
+
+ // copy the netbios name ... adding the scope too
+ pGeneral = (tGENERALRR *)DnsStoreName(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ pName,
+ pTracker->pchDomainName,
+ eNsType);
+
+ pGeneral->Question.QuestionTypeClass = htonl(QUEST_DNSINTERNET);
+
+ pNameHdr->OpCodeFlags = (FL_RECURDESIRE);
+
+ pNameHdr->ArCount = 0;
+
+ // we just need to return something non-null to succeed.
+ return((PULONG)pNameHdr);
+#endif
+
+ case eNAME_QUERY:
+
+ if (NodeType & BNODE)
+ {
+ pNameHdr->OpCodeFlags = (FL_BROADCAST | FL_RECURDESIRE);
+ }
+ else
+ pNameHdr->OpCodeFlags = (FL_RECURDESIRE);
+
+ pNameHdr->ArCount = 0;
+
+ // we just need to return something non-null to succeed.
+ return((PULONG)pNameHdr);
+ break;
+
+ case eNAME_REGISTRATION_OVERWRITE:
+ case eNAME_REFRESH:
+ case eNAME_REGISTRATION:
+ //
+ // The broadcast bit is set in UdpSendNSBcast so we don't
+ // need to set it here. - just set the op code, since the broadcast
+ // bit is a function of whether we are talking to the nameserver or doing
+ // a broadcast. This code handles the multi-homed case with a new
+ // opcode for registration, and that opcode is set in the routine that
+ //
+ // The final name registration in Broadcast is called an Overwrite request
+ // and it does not have the FL_RECURSION Desired bit set.
+ //
+ if (eNsType == eNAME_REGISTRATION_OVERWRITE)
+ {
+ pNameHdr->OpCodeFlags = (OP_REGISTRATION);
+ }
+ else
+ {
+ pNameHdr->OpCodeFlags = (FL_RECURDESIRE | OP_REGISTRATION);
+ }
+
+
+ //
+ // If WINS is on the same machine adjust the PDU to be able to tell
+ // WINS that this pdu came from the local machine
+ //
+#ifndef VXD
+ if (pWinsInfo && (pTracker->Flags & NBT_NAME_SERVER))
+ {
+ pNameHdr->AnCount = (UCHAR)WINS_SIGNATURE;
+ }
+#endif
+ pGeneral->Ttl = htonl(DEFAULT_TTL);
+
+ // *** NOTE: There is no BREAK here by DESIGN!!
+
+ case eNAME_RELEASE:
+ // this code sets the Broadcast bit based on the node type rather than the
+ // type of send....UdpSendNSBcast, resets the code according to the type of
+ // name, so this code may not need to set the Broadcast bit
+ //
+ if (eNsType == eNAME_RELEASE)
+ {
+ pNameHdr->OpCodeFlags = OP_RELEASE;
+ //
+ // TTL for release is zero
+ //
+ pGeneral->Ttl = 0;
+ }
+
+ pNameHdr->ArCount = 1; // 1 additional resource record included
+
+
+ pGeneral->RrName.uSizeLabel = PTR_TO_NAME; // set top two bits to signify ptr
+
+ // the offset ptr to the name added above
+ pGeneral->RrName.pLabel[0] = sizeof(tNAMEHDR) - sizeof(tNETBIOS_NAME);
+ pGeneral->RrTypeClass = htonl(QUEST_NBINTERNET);
+
+
+ pGeneral->Length = htons(6);
+ pGeneral->Flags = htons((USHORT)((NameType << 15) | NbtConfig.PduNodeType));
+ pGeneral->IpAddress = htonl(IpAddress);
+
+ break;
+
+ }
+
+
+ // return the ptr to the IP address so this can be filled in later if necessary
+ return((PVOID)&pGeneral->IpAddress);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+NsDgramSendCompleted(
+ PVOID pContext,
+ NTSTATUS status,
+ ULONG lInfo
+ )
+/*++
+
+Routine Description:
+
+ This routine turns off the bit indicating that the datagram send is
+ still in the transport, so that we will know if it is safe to send another
+ one or not when the timer times out and calls MsNodeCompletion.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+ pTracker->Flags &= ~SEND_PENDING;
+
+ DereferenceTracker(pTracker);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+NameDgramSendCompleted(
+ PVOID pContext,
+ NTSTATUS status,
+ ULONG lInfo
+ )
+/*++
+
+Routine Description:
+
+ This routine frees the name service datagram that was allocated for
+ this name query or name registration in UdpSendNsBcast.
+
+Arguments:
+
+ pContext = ptr to datagram header
+
+Return Value:
+
+
+--*/
+{
+ CTEMemFree(pContext);
+}
+//----------------------------------------------------------------------------
+ VOID
+NDgramSendCompleted(
+ PVOID pContext,
+ NTSTATUS status,
+ ULONG lInfo
+ )
+/*++
+
+Routine Description:
+
+ This routine frees the name service datagram that was allocated for
+ this name query or name registration in UdpSendNsBcast.
+
+Arguments:
+
+ pContext = ptr to datagram header
+
+Return Value:
+
+
+--*/
+{
+ FreeTracker((tDGRAM_SEND_TRACKING *)pContext,FREE_HDR | RELINK_TRACKER);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+UdpSendResponse(
+ IN ULONG lNameSize,
+ IN tNAMEHDR UNALIGNED *pNameHdrIn,
+ IN tNAMEADDR *pNameAddr,
+ IN PTDI_ADDRESS_IP pDestIpAddress,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN ULONG Rcode,
+ IN enum eNSTYPE NsType,
+ IN CTELockHandle OldIrq
+ )
+/*++
+
+Routine Description:
+
+ This routine builds a registration response pdu and sends it with the
+ specified Rcode.
+
+Arguments:
+
+ lSize - number of bytes in the name including scope in half ascii
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ NTSTATUS status;
+ tNAMEHDR *pNameHdr;
+ ULONG uLength;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tQUERYRESP *pQuery;
+ ULONG ToCopy;
+ LONG i;
+ BOOLEAN RespondWithOneAddr = TRUE;
+ ULONG MultiHomedSize = 0;
+ ULONG in_addr;
+ USHORT in_port;
+ ULONG IpAddress;
+ USHORT NameType;
+ BOOLEAN DoNonProxyCode = TRUE;
+
+ in_addr = ntohl(pDestIpAddress->in_addr);
+ in_port = ntohs(pDestIpAddress->sin_port);
+
+ // a multihomed node can have the SingleResponse registry value set so
+ // that it never returns a list of ip addresses. This allows multihoming
+ // in disjoint WINS server domains. - for name Query responses only
+ //
+
+ if ((NbtConfig.MultiHomed) &&
+ (!NbtConfig.SingleResponse) &&
+ (NsType == eNAME_QUERY_RESPONSE))
+ {
+ if (SrcIsNameServer(in_addr,in_port))
+ {
+ RespondWithOneAddr = FALSE;
+ MultiHomedSize = (NbtConfig.AdapterCount-1)*sizeof(tADDSTRUCT);
+ }
+ }
+
+ // size is size of the namehdr structure -1 for NetBiosName[1]
+ // + the 32 bytes for the half ascii name + the Query response record
+ // + any scope size (including the null on the end of the name)
+ // ( part of the lNameSize) + the number of extra adapters * the size
+ // of the address structure (multihomed case).
+ uLength = sizeof(tNAMEHDR)
+ + sizeof(tQUERYRESP)
+ + lNameSize
+ - 1
+ + MultiHomedSize;
+
+ // Note that this memory must be deallocated when the send completes in
+ // tdiout.DgramSendCompletion
+ pNameHdr = NbtAllocMem((USHORT)uLength ,NBT_TAG('Y'));
+ if (!pNameHdr)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ CTEZeroMemory((PVOID)pNameHdr,uLength);
+
+ pNameHdr->QdCount = 0;
+ pNameHdr->AnCount = 1;
+
+ //
+ // fill in the rest of the PDU explicitly
+ //
+ pQuery = (tQUERYRESP *)&pNameHdr->NameRR.NetBiosName[lNameSize];
+
+ pQuery->RrTypeClass = htonl(QUEST_NBINTERNET);
+ pQuery->Ttl = 0;
+ pQuery->Length = htons(sizeof(tADDSTRUCT));
+ pQuery->Flags = htons((USHORT)(NbtConfig.PduNodeType));
+
+ // set the name type to 1 if it is a group so we can shift the 1 to the 16th
+ // bit position
+ //
+ if (pNameAddr != NULL)
+ {
+ NameType = (pNameAddr->NameTypeState & (NAMETYPE_GROUP | NAMETYPE_INET_GROUP)) ? 1 : 0;
+ }
+ pQuery->Flags = htons((USHORT)((NameType << 15) | NbtConfig.PduNodeType));
+
+ // convert Rcode to network order
+ Rcode = htons(Rcode);
+
+ switch (NsType)
+ {
+
+ case eNAME_RELEASE:
+ case eNAME_REGISTRATION_RESPONSE:
+
+ // copy the source name and the 12 bytes preceeding it to complete the
+ // response pdu
+ //
+ ToCopy = sizeof(tNAMEHDR) + lNameSize -1;
+ CTEMemCopy((PVOID)pNameHdr,
+ (PVOID)pNameHdrIn,
+ ToCopy);
+
+ if (NsType == eNAME_RELEASE)
+ {
+ // setup the fields in the response.
+ pNameHdr->OpCodeFlags = (USHORT)(OP_RESPONSE | OP_RELEASE
+ | FL_AUTHORITY
+ | Rcode);
+
+ }
+ else
+ {
+ // setup the fields in the response.
+ pNameHdr->OpCodeFlags = (USHORT)(OP_RESPONSE | OP_REGISTRATION |
+ FL_RECURDESIRE | FL_RECURAVAIL | FL_AUTHORITY
+ | Rcode);
+
+ }
+
+ // these two lines must be here because the memcopy above sets
+ // them to wrong values.
+ pNameHdr->QdCount = 0;
+ pNameHdr->AnCount = 1;
+ pNameHdr->ArCount = 0;
+ pNameHdr->NsCount = 0;
+
+ // this code will run in the proxy case where another node does a
+ // registration of a unique name that conflicts with an internet
+ // group name in the remote table. There are never any internet group
+ // names in the local table - at least if there are, they are flagged
+ // as simple groups.
+ //
+ if (pNameAddr)
+ {
+ if (pNameAddr->NameTypeState & NAMETYPE_INET_GROUP)
+ {
+ IpAddress = pNameAddr->pIpList->IpAddr[0];
+ }
+ else
+ {
+ // an ipaddress of 0 and a group name means it is a local name
+ // table entry, where the 0 ipaddress should be switched to the
+ // ipaddress of this adapter.
+ //
+ if ((pNameAddr->IpAddress == 0) &&
+ (pNameAddr->NameTypeState & NAMETYPE_GROUP))
+ {
+ IpAddress = pDeviceContext->IpAddress;
+ }
+ else
+ IpAddress = pNameAddr->IpAddress;
+ }
+ }
+ else
+ {
+ IpAddress = 0;
+ }
+ break;
+
+ case eNAME_QUERY_RESPONSE:
+
+ pNameHdr->OpCodeFlags = ( OP_RESPONSE | FL_AUTHORITY | FL_RECURDESIRE );
+
+ pNameHdr->TransactId = pNameHdrIn->TransactId;
+
+ // add 1 for the name length byte on the front of the name - scope is already
+ // included in lNameSize
+ //
+ CTEMemCopy(&pNameHdr->NameRR.NameLength,
+ (PVOID)&pNameHdrIn->NameRR.NameLength,
+ lNameSize+1);
+
+
+ if (pNameAddr == NULL)
+ {
+ // this is a negative query response record since there is no
+ // local name to be found
+ //
+ pNameHdr->OpCodeFlags |= htons(NAME_ERROR);
+ pQuery->Length = 0;
+ IpAddress = 0;
+ }
+ else
+ {
+ tDEVICECONTEXT *pDevContext;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ // do not send name query responses for names not registered on
+ // this net card, unless it is the name server for that net
+ // card requesting the name query, since for Multihomed nodes
+ // when it registers a name, WINS will do a query, which may
+ // come in on the other net card that the name is not active on
+ // yet - so we want to respond to this sort of query. Do not do
+ // this check for a proxy since it is responding for a name
+ // in the remote name table and it is not bound to an adapter.
+ //
+ if (!(NodeType & PROXY) &&
+ !(pNameAddr->AdapterMask & pDeviceContext->AdapterNumber) &&
+ (!((in_port == NbtConfig.NameServerPort) &&
+ (pDeviceContext->lNameServerAddress == in_addr) ||
+ (pDeviceContext->lBackupServer == in_addr))))
+
+ {
+ //
+ // Only return an address to the requestor if the
+ // name is registered on that adapter
+ //
+ CTEMemFree(pNameHdr);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ pQuery->Ttl = htonl(DEFAULT_TTL);
+ //
+ // In case of PROXY, we send one IP address as response to an
+ // internet group query. Note: there should not be any INET_GROUP
+ // names in the local hash table, hence a non-proxy should not execute
+ // this code
+ //
+#ifdef PROXY_NODE
+ //
+ // When the proxy responds, the source node will see that it is a
+ // group name and convert it to a broadcast, so the Ip address doesn't
+ // really matter since the sender will not use it. Note that the
+ // source node send may not actually reach any members of the
+ // internet group since they may all be off the local subnet.
+ //
+ IF_PROXY(NodeType)
+ {
+ DoNonProxyCode = FALSE;
+
+ if (pNameAddr->NameTypeState & (NAMETYPE_INET_GROUP))
+ {
+ //
+ // the first address is zero meaning the broadcast address,
+ // so use the second, if there is a second one
+ //
+ if (pNameAddr->pIpList->IpAddr[1] != (ULONG)-1)
+ {
+ IpAddress = pNameAddr->pIpList->IpAddr[1];
+ }
+ else
+ IpAddress = pNameAddr->pIpList->IpAddr[0];
+ }
+
+ //
+ // if this name is local and if this is a multihomed machine
+ // we should treat it like a regular multihomed machine, even
+ // though this is a Proxy node
+ //
+ else if ( (pNameAddr->Verify == LOCAL_NAME) &&
+ (NbtConfig.MultiHomed) )
+ {
+ DoNonProxyCode = TRUE;
+ }
+
+ else
+ {
+ IpAddress = pNameAddr->IpAddress;
+ }
+
+ if (IpAddress == 0)
+ {
+ // don't return 0, return the broadcast address
+ //
+ IpAddress = pDeviceContext->BroadcastAddress;
+ }
+
+ }
+
+ if (DoNonProxyCode)
+#endif
+ {
+ // the node could be multihomed, but we are saying, only
+ // respond with one address when this flag is set.
+ if (RespondWithOneAddr)
+ {
+ // for multihomed hosts, SelectAdapter can be set to TRUE
+ //
+ if (NbtConfig.SelectAdapter)
+ {
+ CTESystemTime TimeValue;
+ LONG Index;
+ ULONG Count=0;
+
+ // we are only going to return one address, but we
+ // can randomly select it from the available adapters
+ // Try to find a valid ip address 5 times.
+ //
+ IpAddress = 0;
+ while ((IpAddress == 0) && (Count < 5))
+ {
+ Count++;
+ CTEQuerySystemTime(TimeValue);
+ Index = RandomizeFromTime( TimeValue, NbtConfig.AdapterCount ) ;
+
+ pHead = &NbtConfig.DeviceContexts;
+ pEntry = pHead->Flink;
+
+ for (i = 0;i< Index;i++)
+ pEntry = pEntry->Flink;
+
+ pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+ IpAddress = pDevContext->IpAddress;
+ }
+
+ //
+ // if this adapter still has a null IpAddress then respond
+ // with the adapter the request came in on, since the
+ // other adapters could be idle RAS or waiting for a DHCP
+ // address just now...
+ //
+ if (IpAddress == 0)
+ {
+ IpAddress = pDeviceContext->IpAddress;
+ }
+ }
+ else
+ {
+ IpAddress = pDeviceContext->IpAddress;
+ }
+ }
+ else
+ {
+ tADDSTRUCT *pAddStruct;
+ USHORT Flags;
+ ULONG Count = 0;
+
+ // multihomed case - go through all the adapters making
+ // up a structure of all adapters that the name is
+ // registered against. Enough memory was allocated up
+ // front to have the name registered against all adapeters
+ // on this node.
+ //
+ Flags = pQuery->Flags;
+
+ // set to zero so we don't try to set pQuery->IpAddress
+ // below
+ IpAddress = 0;
+
+ pAddStruct = (tADDSTRUCT *)&pQuery->Flags;
+ pHead = &NbtConfig.DeviceContexts;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+
+ //
+ // only pass back addresses registered on this adapter
+ // that are not null(i.e. not RAS adapters after a disconnect)
+ //
+ if ((pDevContext->AdapterNumber & pNameAddr->AdapterMask) &&
+ (pDevContext->IpAddress))
+ {
+ pAddStruct->NbFlags = Flags;
+ pAddStruct->IpAddr = htonl(pDevContext->IpAddress);
+ Count++;
+ pAddStruct++;
+ }
+ pEntry = pEntry->Flink;
+
+ }
+ // re-adjust the length of the pdu if the name is not registered
+ // against all adapters...
+ //
+ if (Count != NbtConfig.AdapterCount)
+ {
+ uLength -= (NbtConfig.AdapterCount - Count)*sizeof(tADDSTRUCT);
+ }
+ pQuery->Length = (USHORT)htons(Count*sizeof(tADDSTRUCT));
+ }
+ }
+ }
+
+
+ }
+
+ if (IpAddress)
+ {
+ pQuery->IpAddress = htonl(IpAddress);
+ }
+
+ // get a tracker structure, which has a SendInfo structure in it
+ status = GetTracker(&pTracker);
+ if (!NT_SUCCESS(status))
+ {
+ CTEMemFree((PVOID)pNameHdr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // fill in the connection information
+ pTracker->SendBuffer.HdrLength = uLength;
+ pTracker->SendBuffer.pDgramHdr = (PVOID)pNameHdr;
+ pTracker->SendBuffer.Length = 0;
+ pTracker->SendBuffer.pBuffer = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ status = UdpSendDatagram(pTracker,
+ in_addr,
+ pDeviceContext->pNameServerFileObject,
+ QueryRespDone,
+ pTracker,
+ in_port,
+ NBT_NAME_SERVICE);
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+QueryRespDone(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo)
+/*++
+Routine Description
+
+ This routine handles cleaning up various data blocks used in conjunction
+ with the sending the Query response.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+UdpSendDatagram(
+ IN tDGRAM_SEND_TRACKING *pDgramTracker,
+ IN ULONG IpAddress,
+ IN PFILE_OBJECT TransportFileObject,
+ IN PVOID pCompletionRoutine,
+ IN PVOID CompletionContext,
+ IN USHORT Port,
+ IN ULONG Service
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a datagram across the TDI to be sent by Udp.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ NTSTATUS status;
+ TDI_REQUEST TdiRequest;
+ ULONG uSentSize;
+ TDI_CONNECTION_INFORMATION *pSendInfo;
+ PTRANSPORT_ADDRESS pTransportAddr;
+ ULONG Length;
+
+
+
+ status = STATUS_SUCCESS;
+
+ // when there is no WINS server set in the registry we set the WINS
+ // ip address to LOOP_BACK, so if it is set to that here, do not send
+ // the datagram. If There is no Ip Address then the Transport Handle
+ // will be null and we do not do the send in that case either.
+ //
+ if ((IpAddress == LOOP_BACK) || (!TransportFileObject))
+ {
+ if (pCompletionRoutine)
+ {
+ (*(NBT_COMPLETION)pCompletionRoutine)(CompletionContext,status,0);
+ }
+ return(status);
+ }
+
+ pSendInfo = pDgramTracker->pSendInfo;
+ //
+ // an address of 0 means do a broadcast. When '1C' internet group
+ // names are built either from the Lmhost file or from the network
+ // the broadcast address is inserted in the list as 0.
+ //
+ if (IpAddress == 0)
+ {
+ IpAddress = pDgramTracker->pDeviceContext->BroadcastAddress;
+ }
+
+ TdiRequest.Handle.AddressHandle = (PVOID)TransportFileObject;
+
+ // the completion routine is setup to free the pDgramTracker memory block
+ TdiRequest.RequestNotifyObject = pCompletionRoutine;
+ TdiRequest.RequestContext = (PVOID)CompletionContext;
+
+ // the send length is the client dgram length + the size of the dgram
+ // header
+ //
+ Length = pDgramTracker->SendBuffer.HdrLength + pDgramTracker->SendBuffer.Length;
+
+ // fill in the connection information
+ pSendInfo->RemoteAddressLength = sizeof(TRANSPORT_ADDRESS) -1
+ + pNbtGlobConfig->SizeTransportAddress;
+
+ pTransportAddr = (PTRANSPORT_ADDRESS)pSendInfo->RemoteAddress;
+
+ // fill in the remote address
+ pTransportAddr->TAAddressCount = 1;
+ pTransportAddr->Address[0].AddressLength = pNbtGlobConfig->SizeTransportAddress;
+
+ pTransportAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+
+ ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->sin_port = htons(Port);
+
+ ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->in_addr =
+ htonl(IpAddress);
+
+ Service = NBT_NAME_SERVICE;
+ status = TdiSendDatagram(
+ &TdiRequest,
+ pSendInfo,
+ Length,
+ &uSentSize,
+ &pDgramTracker->SendBuffer,
+ Service);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TcpSessionStart(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN ULONG IpAddress,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pCompletionRoutine,
+ IN ULONG Port
+ )
+/*++
+
+Routine Description:
+
+ This routine sets up a tcp connection by passing a connect through TDI to
+ TCP.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ NTSTATUS status;
+ TDI_REQUEST TdiRequest;
+ TDI_CONNECTION_INFORMATION *pSendInfo;
+ PTRANSPORT_ADDRESS pTransportAddr;
+ tCONNECTELE *pConnEle;
+ CTELockHandle OldIrq;
+ tLOWERCONNECTION *pLowerConn;
+
+ pSendInfo = pTracker->pSendInfo;
+
+ // we need to pass the file handle of the connection to TCP.
+ pConnEle = (tCONNECTELE *)pTracker->Connect.pConnEle;
+
+ CTESpinLock(pConnEle,OldIrq);
+ pLowerConn = pConnEle->pLowerConnId;
+ if (pLowerConn)
+ {
+ TdiRequest.Handle.AddressHandle =
+ (PVOID)((tLOWERCONNECTION *)pConnEle->pLowerConnId)->pFileObject;
+
+ // the completion routine is setup to free the pTracker memory block
+ TdiRequest.RequestNotifyObject = pCompletionRoutine;
+ TdiRequest.RequestContext = (PVOID)pTracker;
+
+ // fill in the connection information
+ pSendInfo->RemoteAddressLength = sizeof(TRANSPORT_ADDRESS) -1
+ + pNbtGlobConfig->SizeTransportAddress;
+
+ pTransportAddr = (PTRANSPORT_ADDRESS)pSendInfo->RemoteAddress;
+
+ // fill in the remote address
+ pTransportAddr->TAAddressCount = 1;
+ pTransportAddr->Address[0].AddressLength = pNbtGlobConfig->SizeTransportAddress;
+ pTransportAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+ ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->sin_port =
+ htons((USHORT)Port);
+
+ ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->in_addr =
+ htonl(IpAddress);
+
+ CTESpinFree(pConnEle,OldIrq);
+
+ // pass through the TDI I/F on the bottom of NBT, to the transport
+ // pass in the original irp from the client so that the client can
+ // cancel it ok...rather than use one of NBT's irps
+ //
+ status = TdiConnect(
+ &TdiRequest,
+ (ULONG)pTracker->Connect.pTimeout,
+ pSendInfo,
+ pConnEle->pIrp);
+
+ }
+ else
+ {
+ CTESpinFree(pConnEle,OldIrq);
+ //
+ // Complete the request through the completion routine so it
+ // cleans up correctly
+ //
+ (*(NBT_COMPLETION)pCompletionRoutine)(
+ (PVOID)pTracker,
+ STATUS_CANCELLED,
+ 0L
+ );
+
+ status = STATUS_CANCELLED;
+ }
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TcpSendSessionResponse(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG lStatusCode,
+ IN ULONG lSessionStatus
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a session PDU corresponding to the lStatusCode. This
+ could be a KeepAlive, PositiveSessionResponse, NegativeSessionResponse or
+ a Retarget (not implemented yet). For the Keep Alive case the completion
+ routine passed in is used rather than SessionRespDone, as is the case
+ for all other messages.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tSESSIONERROR *pSessionHdr;
+
+ pSessionHdr = (tSESSIONERROR *)NbtAllocMem(sizeof(tSESSIONERROR),NBT_TAG('Z'));
+ if (!pSessionHdr)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // get a tracker structure, which has a SendInfo structure in it
+ status = GetTracker(&pTracker);
+ if (NT_SUCCESS(status))
+ {
+ pTracker->SendBuffer.pDgramHdr = (PVOID)pSessionHdr;
+ pTracker->SendBuffer.pBuffer = NULL;
+ pTracker->SendBuffer.Length = 0;
+
+ pSessionHdr->Flags = NBT_SESSION_FLAGS;
+ pSessionHdr->Type = (UCHAR)lStatusCode;
+
+ switch (lStatusCode)
+ {
+ case NBT_NEGATIVE_SESSION_RESPONSE:
+ pTracker->SendBuffer.HdrLength = sizeof(tSESSIONERROR);
+ // this length is one byte longer for the error code - different type used here
+ pSessionHdr->Length = htons(1); // one error code byte
+ pSessionHdr->ErrorCode = (UCHAR)lSessionStatus;
+ break;
+
+ case NBT_POSITIVE_SESSION_RESPONSE:
+ pTracker->SendBuffer.HdrLength = sizeof(tSESSIONHDR);
+ pSessionHdr->Length = 0; // no data following the length byte
+ break;
+
+ }
+
+ status = TcpSendSession(pTracker,
+ pLowerConn,
+ SessionRespDone);
+ }
+ else
+ {
+ CTEMemFree((PVOID)pSessionHdr);
+ }
+
+ return(status);
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TcpSendSession(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN PVOID pCompletionRoutine
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a message on a tcp connection.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ NTSTATUS status;
+ TDI_REQUEST TdiRequest;
+ ULONG lSentLength;
+
+ // we need to pass the file handle of the connection to TCP.
+ TdiRequest.Handle.AddressHandle = (PVOID)pLowerConn->pFileObject;
+
+ // the completion routine is setup to free the pTracker memory block
+ TdiRequest.RequestContext = (PVOID)pTracker;
+
+ // this completion routine just puts the tracker back on its list and
+ // frees the memory associated with the UserData buffer.
+ TdiRequest.RequestNotifyObject = pCompletionRoutine;
+
+ // pass through the TDI I/F on the bottom of NBT, to the transport
+ status = TdiSend(
+ &TdiRequest,
+ 0, // no send flags
+ (ULONG)pTracker->SendBuffer.HdrLength +
+ (ULONG)pTracker->SendBuffer.Length ,
+ &lSentLength,
+ &pTracker->SendBuffer,
+ 0); // no send flags set
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SessionRespDone(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo)
+/*++
+Routine Description
+
+ This routine handles cleaning up various data blocks used in conjunction
+ sending a session response at session startup time. If the session
+ response was negative, then kill the connection.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+ NTSTATUS - completion status
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+SendTcpDisconnect(
+ IN tLOWERCONNECTION *pLowerConnId
+ )
+/*++
+Routine Description
+
+ This routine disconnects a TCP connection in a graceful manner which
+ insures that any data still in the pipe gets to the other side. Mostly
+ it calls TcpDisconnect which does the work. This routine just gets a
+ tracker for the send.
+
+Arguments:
+
+ pLowerConnID - ptr to the lower connection that has the file object in it
+
+Return Values:
+ NTSTATUS - completion status
+
+ VOID
+
+--*/
+
+{
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+
+ status = GetTracker(&pTracker);
+ if (NT_SUCCESS(status))
+ {
+ pTracker->Connect.pConnEle = (PVOID)pLowerConnId;
+
+ status = TcpDisconnect(pTracker,NULL,TDI_DISCONNECT_RELEASE,FALSE);
+ }
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TcpDisconnect(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PVOID Timeout,
+ IN ULONG Flags,
+ IN BOOLEAN Wait
+ )
+/*++
+Routine Description
+
+ This routine disconnects a TCP connection in a graceful manner which
+ insures that any data still in the pipe gets to the other side.
+
+Arguments:
+
+ pTracker - ptr to the DGRAM_TRACKER block
+
+Return Values:
+ NTSTATUS - completion status
+
+ VOID
+
+--*/
+
+{
+ TDI_REQUEST TdiRequest;
+ NTSTATUS status;
+
+ // we need to pass the file handle of the connection to TCP.
+ TdiRequest.Handle.AddressHandle =
+ (PVOID)((tLOWERCONNECTION *)pTracker->Connect.pConnEle)->pFileObject;
+
+ // the completion routine is setup to free the pTracker memory block
+ TdiRequest.RequestContext = (PVOID)pTracker;
+
+ // this completion routine just puts the tracker back on its list and
+ // frees the memory associated with the UserData buffer.
+ TdiRequest.RequestNotifyObject = DisconnectDone;
+ pTracker->Flags = (USHORT)Flags;
+
+ status = TdiDisconnect(&TdiRequest,
+ Timeout,
+ Flags,
+ pTracker->pSendInfo,
+ ((tLOWERCONNECTION *)pTracker->Connect.pConnEle)->pIrp,
+ Wait);
+
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+DisconnectDone(
+ IN PVOID pContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo)
+/*++
+Routine Description
+
+ This routine handles cleaning up after a disconnect is sent to the transport.
+
+Arguments:
+
+ pContext - ptr to the DGRAM_TRACKER block
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ tLOWERCONNECTION *pLowerConn;
+ CTELockHandle OldIrq;
+ PCTE_IRP pIrp;
+ BOOLEAN CleanupLower;
+ NTSTATUS DiscWaitStatus;
+ tCONNECTELE *pConnEle;
+ PCTE_IRP pIrpClose;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+
+ pLowerConn = (tLOWERCONNECTION *)pTracker->Connect.pConnEle;
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CTESpinLockAtDpc(pLowerConn);
+
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Disconnect Irp has been returned...pLowerConn %X,state %X\n",
+ pLowerConn,pLowerConn->State));
+ //
+ // if the state is disconnected, then a disconnect indication
+ // has come from the transport.. . if still disconnecting,
+ // then we have not had a disconnect indication yet, so
+ // wait for the indication to go through DisconnectHndlrNotOs which
+ // will do the cleanup.
+ //
+
+ // Streams TCP always indicates before completing the disconnect request,
+ // so we always cleanup here for the Streams stack.
+ //
+ if (StreamsStack)
+ {
+ goto StreamsCode;
+ }
+
+ //
+ // If the disconnect was abortive, then there will not be a disconnect
+ // indication, so do the cleanup now.
+ //
+ if ((pLowerConn->State == NBT_DISCONNECTING)
+ && (pTracker->Flags == TDI_DISCONNECT_RELEASE )
+ && (status == STATUS_SUCCESS) )
+ {
+ pLowerConn->State = NBT_DISCONNECTED ;
+ CleanupLower = FALSE;
+ PUSH_LOCATION(0xA3);
+ }
+ else
+ if (pLowerConn->State != NBT_IDLE)
+ {
+
+StreamsCode:
+
+ //
+ // change the state to idle so that the Disconnect handler will
+ // not attempt to do anything with it if for some reason the transport
+ // indicates a disconnect after this point.
+ //
+ ASSERT((pLowerConn->State == NBT_DISCONNECTED) ||
+ (pLowerConn->State == NBT_DISCONNECTING));
+ pLowerConn->State = NBT_IDLE;
+
+ CleanupLower = TRUE;
+ }
+
+
+ pConnEle = pLowerConn->pUpperConnection;
+
+ //
+ // there may be a disconnect wait irp, so return that first if there
+ // is one waiting around.
+ //
+ if (pConnEle && pConnEle->pIrpClose)
+ {
+ pIrpClose = pConnEle->pIrpClose;
+ CHECK_PTR(pConnEle);
+ pConnEle->pIrpClose = NULL ;
+ if (pConnEle->DiscFlag == TDI_DISCONNECT_ABORT)
+ {
+ DiscWaitStatus = STATUS_CONNECTION_RESET;
+ }
+ else
+ DiscWaitStatus = STATUS_GRACEFUL_DISCONNECT;
+ }
+ else
+ pIrpClose = NULL;
+
+ //
+ // This is the disconnect requesting Irp
+ //
+ if ( pLowerConn->pIrp )
+ {
+ pIrp = pLowerConn->pIrp;
+ pLowerConn->pIrp = NULL ;
+
+ }
+ else
+ pIrp = NULL;
+
+ CTESpinFreeAtDpc(pLowerConn);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ if (pIrpClose)
+ {
+ CTEIoComplete( pIrpClose, DiscWaitStatus, 0 ) ;
+ }
+
+ if (pIrp)
+ {
+ CTEIoComplete( pIrp, status, 0 ) ;
+ }
+
+ if (CleanupLower)
+ {
+ PUSH_LOCATION(0x6c);
+#if !defined(VXD) && DBG
+ //
+ // DEBUG to catch upper connections being put on lower conn QUEUE
+ //
+ if ((pLowerConn->Verify != NBT_VERIFY_LOWERCONN ) ||
+ (pLowerConn->RefCount == 1))
+ {
+ DbgBreakPoint();
+ }
+#else
+ ASSERT(pLowerConn->Verify == NBT_VERIFY_LOWERCONN);
+ ASSERT(pLowerConn->RefCount > 1);
+#endif
+
+ // this either puts the lower connection back on its free
+ // queue if inbound, or closes the connection with the transport
+ // if out bound. (it can't be done at dispatch level).
+ //
+ status = CTEQueueForNonDispProcessing(NULL,
+ pLowerConn,
+ NULL,
+ CleanupAfterDisconnect,
+ pLowerConn->pDeviceContext);
+ }
+
+ FreeTracker(pTracker,RELINK_TRACKER);
+
+}
+
diff --git a/private/ntos/nbt/nbt/up/makefile b/private/ntos/nbt/nbt/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/nbt/nbt/up/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/nbt/nbt/up/sources b/private/ntos/nbt/nbt/up/sources
new file mode 100644
index 000000000..91036a15a
--- /dev/null
+++ b/private/ntos/nbt/nbt/up/sources
@@ -0,0 +1,27 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+!include ..\sources.inc
diff --git a/private/ntos/nbt/nbtprocs.h b/private/ntos/nbt/nbtprocs.h
new file mode 100644
index 000000000..fb00f12e4
--- /dev/null
+++ b/private/ntos/nbt/nbtprocs.h
@@ -0,0 +1,12 @@
+/*
+
+ This is the dummy project header file for generating the
+ pre-compiled header files for NT builds of NetBT.SYS.
+
+ It is not actually included by any of the source files
+ in the driver.
+
+ */
+
+
+#include "inc\nbtprocs.h"
diff --git a/private/ntos/nbt/nt/autodial.c b/private/ntos/nbt/nt/autodial.c
new file mode 100644
index 000000000..9b83f526d
--- /dev/null
+++ b/private/ntos/nbt/nt/autodial.c
@@ -0,0 +1,723 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ autodial.c
+
+Abstract:
+
+ This file provides routines for interacting
+ with the automatic connection driver (acd.sys).
+
+Author:
+
+ Anthony Discolo (adiscolo) 9-6-95
+
+Revision History:
+
+--*/
+#include "nbtprocs.h" // procedure headings
+
+#ifdef RASAUTODIAL
+
+#ifndef VXD
+#include <nbtioctl.h>
+#include <acd.h>
+#include <acdapi.h>
+#endif
+
+//
+// Automatic connection global variables.
+//
+BOOLEAN fAcdLoadedG;
+ACD_DRIVER AcdDriverG;
+ULONG ulDriverIdG = 'Nbt ';
+
+//
+// Imported routines.
+//
+VOID
+CleanUpPartialConnection(
+ IN NTSTATUS status,
+ IN tCONNECTELE *pConnEle,
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PIRP pClientIrp,
+ IN CTELockHandle irqlJointLock,
+ IN CTELockHandle irqlConnEle
+ );
+
+NTSTATUS
+NbtConnectCommon(
+ IN TDI_REQUEST *pRequest,
+ IN PVOID pTimeout,
+ IN PTDI_CONNECTION_INFORMATION pCallInfo,
+ IN PTDI_CONNECTION_INFORMATION pReturnInfo,
+ IN PIRP pIrp
+ );
+
+
+
+VOID
+NbtRetryPreConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called indirectly by the automatic
+ connection driver to continue the connection process
+ after an automatic connection has been made.
+
+Arguments:
+
+ fSuccess - TRUE if the connection attempt was successful.
+
+ pArgs - a pointer to the argument vector
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ tCONNECTELE *pConnEle = pArgs[0];
+ PVOID pTimeout = pArgs[1];
+ PTDI_CONNECTION_INFORMATION pCallInfo = pArgs[2];
+ PTDI_CONNECTION_INFORMATION pReturnInfo = pArgs[3];
+ PIRP pIrp = pArgs[4];
+ TDI_REQUEST request;
+ KIRQL irql;
+ CTELockHandle OldIrq;
+
+#ifdef notdef // DBG
+ DbgPrint(
+ "NbtRetryPreConnect: fSuccess=%d, pIrp=0x%x, pIrp->Cancel=%d, pConnEle=0x%x\n",
+ fSuccess,
+ pIrp,
+ pIrp->Cancel,
+ pConnEle);
+#endif
+ request.Handle.ConnectionContext = pConnEle;
+ status = NTCancelCancelRoutine ( pIrp );
+ if ( status != STATUS_CANCELLED )
+ {
+ //
+ // We're done with the connection progress,
+ // so clear the fAutoConnecting flag. We
+ // set the fAutoConnected flag to prevent us
+ // from re-attempting another automatic
+ // connection on this connection.
+ //
+ CTESpinLock(pConnEle,OldIrq);
+ pConnEle->fAutoConnecting = FALSE;
+ pConnEle->fAutoConnected = TRUE;
+ CTESpinFree(pConnEle,OldIrq);
+
+ status = fSuccess ?
+ NbtConnectCommon(
+ &request,
+ pTimeout,
+ pCallInfo,
+ pReturnInfo,
+ pIrp) :
+ STATUS_BAD_NETWORK_PATH;
+ //
+ // We are responsible for completing
+ // the irp.
+ //
+ if (status != STATUS_PENDING) {
+ //
+ // Clear out the Irp pointer in the Connection object so that we dont try to
+ // complete it again when we clean up the connection. Do this under the connection
+ // lock.
+ //
+ CTESpinLock(pConnEle,OldIrq);
+
+ pConnEle->pIrp = NULL;
+
+ CTESpinFree(pConnEle,OldIrq);
+
+ pIrp->IoStatus.Status = status;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ }
+ }
+} // NbtRetryPreConnect
+
+
+
+BOOLEAN
+NbtCancelAutoDialRequest(
+ IN PVOID pArg,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN USHORT nArgs,
+ IN PVOID *pArgs
+ )
+{
+ if (nArgs != 5)
+ return FALSE;
+
+ return (pArgs[4] == pArg);
+} // NbtCancelAutoDialRequest
+
+
+
+BOOLEAN
+NbtCancelPreConnect(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION pIrpSp;
+ tCONNECTELE *pConnEle;
+ KIRQL irql;
+ ACD_ADDR addr;
+ BOOLEAN fCanceled;
+
+ UNREFERENCED_PARAMETER(pDeviceObject);
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
+ if (pConnEle == NULL)
+ return FALSE;
+#ifdef notdef // DBG
+ DbgPrint("NbtCancelPreConnect: pIrp=0x%x, pConnEle=0x%x\n",
+ pIrp,
+ pConnEle);
+#endif
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnEle->RemoteName, 16);
+ //
+ // Cancel the autodial request.
+ //
+ fCanceled = (*AcdDriverG.lpfnCancelConnection)(
+ ulDriverIdG,
+ &addr,
+ NbtCancelAutoDialRequest,
+ pIrp);
+ if (fCanceled)
+ IoSetCancelRoutine(pIrp, NULL);
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ //
+ // If the request could not be found
+ // in the driver, then it has already
+ // been completed, so we simply return.
+ //
+ if (!fCanceled)
+ return FALSE;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &irql);
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ pIrp->IoStatus.Information = 0;
+
+ {
+ //
+ // Clear out the Irp pointer in the Connection object so that we dont try to
+ // complete it again when we clean up the connection. Do this under the connection
+ // lock.
+ //
+ // BUGBUG[WISHLIST] This should not be needed since before we call NbtConnectCommon, the Cancel routine
+ // is NULLed out, so it cannot happen that the pIrp ptr in the connection is set to the
+ // Irp, and this cancel routine is called.
+ //
+ CTELockHandle OldIrq;
+
+ CTESpinLock(pConnEle,OldIrq);
+
+ pConnEle->pIrp = NULL;
+
+ CTESpinFree(pConnEle,OldIrq);
+ }
+
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ KeLowerIrql(irql);
+
+ return TRUE;
+} // NbtCancelPreConnect
+
+
+
+VOID
+NbtRetryPostConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called indirectly by the automatic
+ connection driver to continue the connection process
+ after an automatic connection has been made.
+
+Arguments:
+
+ fSuccess - TRUE if the connection attempt was successful.
+
+ pArgs - a pointer to the argument vector
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ tCONNECTELE *pConnEle = pArgs[0];
+ PVOID pTimeout = pArgs[1];
+ PTDI_CONNECTION_INFORMATION pCallInfo = pArgs[2];
+ PTDI_CONNECTION_INFORMATION pReturnInfo = pArgs[3];
+ PIRP pIrp = pArgs[4];
+ tDGRAM_SEND_TRACKING *pTracker = (tDGRAM_SEND_TRACKING *)pReturnInfo;
+ TDI_REQUEST request;
+ CTELockHandle irqlConnEle, irqlJointLock;
+ KIRQL irql;
+
+#ifdef notdef // DBG
+ DbgPrint(
+ "NbtRetryPostConnect: fSuccess=%d, pIrp=0x%x, pIrp->Cancel=%d, pConnEle=0x%x\n",
+ fSuccess,
+ pIrp,
+ pIrp->Cancel,
+ pConnEle);
+#endif
+ if (fSuccess) {
+ //
+ // We set the state here to fool NbtConnect
+ // into doing a reconnect.
+ //
+ request.Handle.ConnectionContext = pConnEle;
+ pConnEle->state = NBT_ASSOCIATED;
+ status = NTCancelCancelRoutine ( pIrp );
+ if ( status != STATUS_CANCELLED )
+ {
+ status = NbtConnectCommon(
+ &request,
+ pTimeout,
+ pCallInfo,
+ pReturnInfo,
+ pIrp);
+ //
+ // We are responsible for completing
+ // the irp.
+ //
+ if (status != STATUS_PENDING) {
+ //
+ // Clear out the Irp pointer in the Connection object so that we dont try to
+ // complete it again when we clean up the connection. Do this under the connection
+ // lock.
+ //
+ CTELockHandle OldIrq;
+
+ CTESpinLock(pConnEle,OldIrq);
+
+ ASSERT(pIrp == pConnEle->pIrp);
+ pConnEle->pIrp = NULL;
+
+ CTESpinFree(pConnEle, OldIrq);
+
+ pIrp->IoStatus.Status = status;
+ IoCompleteRequest(pIrp, IO_NO_INCREMENT);
+ }
+ }
+ }
+ else {
+ CTESpinLock(&NbtConfig.JointLock,irqlJointLock);
+ CTESpinLock(pConnEle,irqlConnEle);
+ CleanUpPartialConnection(
+ STATUS_BAD_NETWORK_PATH,
+ pConnEle,
+ pTracker,
+ pIrp,
+ irqlJointLock,
+ irqlConnEle);
+ }
+} // NbtRetryPostConnect
+
+
+
+VOID
+NbtCancelPostConnect(
+ IN PIRP pIrp
+ )
+{
+ PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ tCONNECTELE *pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
+ ACD_ADDR addr;
+
+ if (pConnEle == NULL)
+ return;
+#ifdef notdef // DBG
+ DbgPrint(
+ "NbtCancelPostConnect: pIrp=0x%x, pConnEle=0x%x\n",
+ pIrp,
+ pConnEle);
+#endif
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnEle->RemoteName, 15);
+ //
+ // Cancel the autodial request.
+ //
+ (*AcdDriverG.lpfnCancelConnection)(
+ ulDriverIdG,
+ &addr,
+ NbtCancelAutoDialRequest,
+ pIrp);
+} // NbtCancelPostConnect
+
+
+
+BOOLEAN
+NbtAttemptAutoDial(
+ IN tCONNECTELE *pConnEle,
+ IN PVOID pTimeout,
+ IN PTDI_CONNECTION_INFORMATION pCallInfo,
+ IN PTDI_CONNECTION_INFORMATION pReturnInfo,
+ IN PIRP pIrp,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc
+ )
+
+/*++
+
+Routine Description:
+
+ Call the automatic connection driver to attempt an
+ automatic connection. The first five parameters are
+ used in the call to NbtConnect after the connection
+ completes successfully.
+
+Arguments:
+
+ ...
+
+ ulFlags - automatic connection flags
+
+ pProc - callback procedure when the automatic connection completes
+
+Return Value:
+
+ TRUE if the automatic connection was started successfully,
+ FALSE otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ BOOLEAN fSuccess;
+ ACD_ADDR addr;
+ KIRQL irql;
+ PVOID pArgs[5];
+ PTRANSPORT_ADDRESS pRemoteAddress;
+ PTA_NETBIOS_ADDRESS pRemoteNetBiosAddress;
+ PTA_NETBIOS_EX_ADDRESS pRemoteNetbiosExAddress;
+ ULONG tdiAddressType;
+ PCHAR pName;
+ ULONG ulcbName;
+ LONG lNameType;
+
+ //
+ // If this connection has already been through the
+ // automatic connection process, don't do it again.
+ //
+ if (pCallInfo == NULL || pConnEle->fAutoConnected)
+ return FALSE;
+ //
+ // Get the address of the connection.
+ //
+ pRemoteAddress = (PTRANSPORT_ADDRESS)pCallInfo->RemoteAddress;
+ tdiAddressType = pRemoteAddress->Address[0].AddressType;
+ if (tdiAddressType == TDI_ADDRESS_TYPE_NETBIOS_EX) {
+ PTDI_ADDRESS_NETBIOS pNetbiosAddress;
+
+ pRemoteNetbiosExAddress = (PTA_NETBIOS_EX_ADDRESS)pRemoteAddress;
+ pNetbiosAddress = &pRemoteNetbiosExAddress->Address[0].Address[0].NetbiosAddress;
+ pName = pNetbiosAddress->NetbiosName;
+ lNameType = pNetbiosAddress->NetbiosNameType;
+ ulcbName = pRemoteNetbiosExAddress->Address[0].AddressLength -
+ FIELD_OFFSET(TDI_ADDRESS_NETBIOS_EX,NetbiosAddress) -
+ FIELD_OFFSET(TDI_ADDRESS_NETBIOS,NetbiosName);
+ IF_DBG(NBT_DEBUG_NETBIOS_EX) {
+ KdPrint((
+ "NetBt:NETBIOS address ulNameLen(%ld) Name %16s\n",
+ ulcbName,
+ pName));
+ }
+ status = STATUS_SUCCESS;
+ }
+ else if (tdiAddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ pRemoteNetBiosAddress = (PTA_NETBIOS_ADDRESS)pRemoteAddress;
+ status = GetNetBiosNameFromTransportAddress(
+ pRemoteNetBiosAddress,
+ &pName,
+ &ulcbName,
+ &lNameType);
+ }
+ else
+ status = STATUS_INVALID_ADDRESS_COMPONENT;
+ //
+ // Save the address for pre-connect attempts,
+ // because if we have to cancel this irp,
+ // it is not saved anywhere else.
+ //
+ CTESpinLock(pConnEle, irql);
+ CTEMemCopy(pConnEle->RemoteName, pName, NETBIOS_NAME_SIZE);
+ CTESpinFree(pConnEle, irql);
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pName, NETBIOS_NAME_SIZE);
+#ifdef DBG
+ DbgPrint("NbtAttemptAutodial: szAddr=%-15.15s\n", pName);
+#endif
+ //
+ // Enqueue this request on the network
+ // connection pending queue.
+ //
+ pArgs[0] = pConnEle;
+ pArgs[1] = pTimeout;
+ pArgs[2] = pCallInfo;
+ pArgs[3] = pReturnInfo;
+ pArgs[4] = pIrp;
+ fSuccess = (*AcdDriverG.lpfnStartConnection)(
+ ulDriverIdG,
+ &addr,
+ ulFlags,
+ pProc,
+ 5,
+ pArgs);
+ if (fSuccess) {
+ //
+ // We set the automatic connection in progress
+ // flag so we know to clean up the connection
+ // block in the automatic connection driver if
+ // the request gets canceled.
+ //
+ CTESpinLock(pConnEle, irql);
+ pConnEle->fAutoConnecting = TRUE;
+ CTESpinFree(pConnEle, irql);
+ }
+
+ return fSuccess;
+} // NbtAttemptAutoDial
+
+
+
+VOID
+NbtNoteNewConnection(
+ IN tCONNECTELE *pConnEle,
+ IN tNAMEADDR *pNameAddr
+ )
+
+/*++
+
+Routine Description:
+
+ Inform the automatic connection driver of a
+ successful new connection.
+
+Arguments:
+
+ pConnEle - a pointer to the upper connection
+
+ pNameAddr - a pointer to the remote name
+
+Return Value:
+ None.
+
+--*/
+
+{
+ KIRQL irql;
+ ACD_ADDR addr;
+ ACD_ADAPTER adapter;
+
+ if (pConnEle == NULL || pConnEle->pClientEle == NULL ||
+ pConnEle->pClientEle->pDeviceContext == NULL)
+ {
+ return;
+ }
+ //
+ // Get the source IP address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pNameAddr->Name, 15);
+ adapter.fType = ACD_ADAPTER_IP;
+ adapter.ulIpaddr = 0;
+ CTESpinLock(pConnEle, irql);
+ adapter.ulIpaddr = htonl(pConnEle->pClientEle->pDeviceContext->IpAddress);
+ CTESpinFree(pConnEle, irql);
+ //
+ // If the connection did not have a
+ // TCP connection associated with it,
+ // then we're done.
+ //
+ if (adapter.ulIpaddr == 0)
+ return;
+ (*AcdDriverG.lpfnNewConnection)(&addr, &adapter);
+} // NbtNoteNewConnection
+
+
+
+VOID
+NbtAcdBind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Initialize our part of the ACD_DRIVER
+ // structure.
+ //
+ KeInitializeSpinLock(&AcdDriverG.SpinLock);
+ AcdDriverG.ulDriverId = ulDriverIdG;
+ AcdDriverG.fEnabled = FALSE;
+ //
+ // Build a request to get the automatic
+ // connection driver entry points.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_BIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ fAcdLoadedG = (status == STATUS_SUCCESS);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbtAcdBind
+
+
+
+VOID
+NbtAcdUnbind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Don't bother to unbind if we
+ // didn't successfully bind in the
+ // first place.
+ //
+ if (!fAcdLoadedG)
+ return;
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Build a request to unbind from
+ // the automatic connection driver.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_UNBIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbtAcdUnbind
+
+#endif // RASAUTODIAL
diff --git a/private/ntos/nbt/nt/ctestuff.c b/private/ntos/nbt/nt/ctestuff.c
new file mode 100644
index 000000000..0d9813a6d
--- /dev/null
+++ b/private/ntos/nbt/nt/ctestuff.c
@@ -0,0 +1,90 @@
+//
+//
+// CTESTUFF.C
+//
+// This file contains Common Transport Environment code to handle
+// OS dependent functions such as allocating memory etc.
+//
+//
+#include "nbtprocs.h"
+
+// to convert a millisecond to a 100ns time
+//
+#define MILLISEC_TO_100NS 10000
+
+
+//----------------------------------------------------------------------------
+ PVOID
+CTEStartTimer(
+ IN CTETimer *pTimerIn,
+ IN ULONG DeltaTime,
+ IN CTEEventRtn TimerExpiry,
+ IN PVOID Context OPTIONAL
+ )
+/*++
+Routine Description:
+
+ This Routine starts a timer.
+
+Arguments:
+
+ Timer - Timer structure
+ TimerExpiry - completion routine
+
+Return Value:
+
+ PVOID - a pointer to the memory or NULL if a failure
+
+--*/
+
+{
+ LARGE_INTEGER Time;
+
+ //
+ // initialize the DPC to have the correct completion routine and context
+ //
+ KeInitializeDpc(&pTimerIn->t_dpc,
+ (PVOID)TimerExpiry, // completion routine
+ Context); // context value
+
+ //
+ // convert to 100 ns units by multiplying by 10,000
+ //
+ Time.QuadPart = UInt32x32To64(DeltaTime,(LONG)MILLISEC_TO_100NS);
+
+ //
+ // to make a delta time, negate the time
+ //
+ Time.QuadPart = -(Time.QuadPart);
+
+ ASSERT(Time.QuadPart < 0);
+
+ (VOID)KeSetTimer(&pTimerIn->t_timer,Time,&pTimerIn->t_dpc);
+
+ return(NULL);
+}
+//----------------------------------------------------------------------------
+ VOID
+CTEInitTimer(
+ IN CTETimer *pTimerIn
+ )
+/*++
+Routine Description:
+
+ This Routine initializes a timer.
+
+Arguments:
+
+ Timer - Timer structure
+ TimerExpiry - completion routine
+
+Return Value:
+
+ PVOID - a pointer to the memory or NULL if a failure
+
+--*/
+
+{
+ KeInitializeTimer(&pTimerIn->t_timer);
+}
+
diff --git a/private/ntos/nbt/nt/dirs b/private/ntos/nbt/nt/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/nbt/nt/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/nbt/nt/driver.c b/private/ntos/nbt/nt/driver.c
new file mode 100644
index 000000000..0294ea69b
--- /dev/null
+++ b/private/ntos/nbt/nt/driver.c
@@ -0,0 +1,1228 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Driver.c
+
+Abstract:
+
+ This module implements the DRIVER_INITIALIZATION routine for the
+ NBT Transport and other routines that are specific to the NT implementation
+ of a driver.
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+
+#include "nbtprocs.h"
+#include <nbtioctl.h>
+
+#if DBG
+// allocate storage for the global debug flag NbtDebug
+#ifdef _PNP_POWER
+ULONG NbtDebug=NBT_DEBUG_PNP_POWER; // NT PNP debugging
+#else // _PNP_POWER
+ULONG NbtDebug=0x00000000; // disable all debugging
+#endif // _PNP_POWER
+#endif // DBG
+
+ NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+NTSTATUS
+NbtDispatchCleanup(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP irp
+ );
+
+NTSTATUS
+NbtDispatchClose(
+ IN PDEVICE_OBJECT device,
+ IN PIRP irp
+ );
+
+NTSTATUS
+NbtDispatchCreate(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+NbtDispatchDevCtrl(
+ IN PDEVICE_OBJECT device,
+ IN PIRP irp
+ );
+
+NTSTATUS
+NbtDispatchInternalCtrl(
+ IN PDEVICE_OBJECT device,
+ IN PIRP irp
+ );
+
+PFILE_FULL_EA_INFORMATION
+FindInEA(
+ IN PFILE_FULL_EA_INFORMATION start,
+ IN PCHAR wanted
+ );
+
+VOID
+ReturnIrp(
+ IN PIRP irp,
+ IN int status
+ );
+
+VOID
+MakePending(
+ IN PIRP pIrp
+ );
+
+#ifdef RASAUTODIAL
+VOID
+NbtAcdBind();
+#endif // RASAUTODIAL
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(INIT, DriverEntry)
+#ifdef RASAUTODIAL
+#pragma CTEMakePageable(INIT, NbtAcdBind)
+#endif // RASAUTODIAL
+#pragma CTEMakePageable(PAGE, NbtDispatchCleanup)
+#pragma CTEMakePageable(PAGE, NbtDispatchClose)
+#pragma CTEMakePageable(PAGE, NbtDispatchCreate)
+#pragma CTEMakePageable(PAGE, NbtDispatchDevCtrl)
+#pragma CTEMakePageable(PAGE, FindInEA)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This is the initialization routine for the NBT device driver.
+ This routine creates the device object for the NBT
+ device and calls a routine to perform other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ NTSTATUS - The function value is the final status from the initialization
+ operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ tADDRARRAY *pAddr;
+ tDEVICES *pBindDevices=NULL;
+ tDEVICES *pExportDevices=NULL;
+ tADDRARRAY *pAddrArray=NULL;
+
+#ifndef _PNP_LATER
+ int i;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ NTSTATUS Locstatus;
+ tDEVICECONTEXT *pDeviceContext;
+ ULONG DevicesStarted;
+#endif // _PNP_POWER
+
+ CTEPagedCode();
+
+#ifdef _PNP_POWER
+ TdiInitialize();
+#endif
+
+ //
+ // get the file system process for NBT since we need to know this for
+ // allocating and freeing handles
+ //
+ NbtFspProcess =(PEPROCESS)PsGetCurrentProcess();
+
+ //
+ // read in registry configuration data
+ //
+ status = NbtReadRegistry(RegistryPath,
+ DriverObject,
+ &NbtConfig,
+ &pBindDevices,
+ &pExportDevices,
+ &pAddrArray);
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("NBT:Fatal Error - Failed registry read! status = %X\n",
+ status));
+ return(status);
+ }
+
+
+ //
+ // Initialize NBT global data.
+ //
+ status = InitNotOs() ;
+ if (!NT_SUCCESS(status))
+ {
+ NbtLogEvent(EVENT_NBT_NON_OS_INIT,status);
+ KdPrint(("NBT:OS Independent initialization failed! status = %X\n",
+ status));
+ return(status);
+ }
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+ DriverObject->MajorFunction[IRP_MJ_CREATE] =
+ (PDRIVER_DISPATCH)NbtDispatchCreate;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
+ (PDRIVER_DISPATCH)NbtDispatchDevCtrl;
+ DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
+ (PDRIVER_DISPATCH)NbtDispatchInternalCtrl;
+
+ DriverObject->MajorFunction[IRP_MJ_CLEANUP] =
+ (PDRIVER_DISPATCH)NbtDispatchCleanup;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] =
+ (PDRIVER_DISPATCH)NbtDispatchClose;
+
+ DriverObject->DriverUnload = NULL;
+
+#ifndef _PNP_LATER
+
+ // start some timers
+ status = InitTimersNotOs();
+
+ if (!NT_SUCCESS(status))
+ {
+ NbtLogEvent(EVENT_NBT_TIMERS,status);
+ KdPrint(("NBT:Failed to Initialize the Timers!,status = %X\n",
+ status));
+ StopInitTimers();
+ return(status);
+ }
+
+// #else // _PNP_POWER
+
+ // ASSERT (status == STATUS_SUCCESS);
+
+ NbtConfig.uDevicesStarted = 0;
+
+#endif // _PNP_POWER
+
+ pNbtGlobConfig->iBufferSize[eNBT_FREE_SESSION_MDLS] = sizeof(tSESSIONHDR);
+ pNbtGlobConfig->iBufferSize[eNBT_DGRAM_MDLS] = DGRAM_HDR_SIZE
+ + (pNbtGlobConfig->ScopeLength << 1);
+
+ // create some MDLs, for session sends to speed up the sends.
+ status = NbtInitMdlQ(
+ &NbtConfig.SessionMdlFreeSingleList,
+ eNBT_FREE_SESSION_MDLS);
+
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("NBT:Failed to Initialize the Session MDL Queue!,status = %X\n",
+ status));
+ return(status);
+ }
+ // create some MDLs for datagram sends
+ status = NbtInitMdlQ(
+ &NbtConfig.DgramMdlFreeSingleList,
+ eNBT_DGRAM_MDLS);
+
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("NBT:Failed to Initialize the Dgram MDL Queue!,status = %X\n",
+ status));
+ return(status);
+ }
+
+#ifndef _PNP_LATER
+
+ //
+ // Create the NBT device object for each adapter configured
+ //
+ pAddr = pAddrArray;
+
+ DevicesStarted = 0;
+
+ for (i=0; i<pNbtGlobConfig->uNumDevices; i++ )
+ {
+
+ // this call ultimately allocates storage for the returned NameString
+ // that holds the Ipaddress
+ status = NbtCreateDeviceObject(
+ DriverObject,
+ pNbtGlobConfig,
+ &pBindDevices->Names[i],
+ &pExportDevices->Names[i],
+ pAddr,
+ RegistryPath,
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ FALSE,
+#endif
+ &pDeviceContext);
+
+ // for a Bnode there are no Wins server addresses, so this Ptr can
+ // be null.
+ if (pAddr)
+ {
+ pAddr++;
+ }
+
+ //
+ // allow not having an address to succeed - DHCP will
+ // provide an address later
+ //
+ if (pDeviceContext != NULL)
+ {
+ if (status == STATUS_INVALID_ADDRESS)
+ {
+ //
+ // set to null so we know not to allow connections or dgram
+ // sends on this adapter
+ //
+ pDeviceContext->IpAddress = 0;
+
+ DevicesStarted++;
+
+ status = STATUS_SUCCESS;
+
+ }
+
+
+ if ((NT_SUCCESS(status)) ||
+ (status == STATUS_INVALID_ADDRESS_COMPONENT)) {
+
+ status = STATUS_SUCCESS;
+ NbtConfig.uDevicesStarted++;
+ }
+
+
+ {
+ //
+ // We can tolerate the invalid address component failure since IP does not know of
+ // static addresses at this time.
+ //
+ if (!NT_SUCCESS(status))
+ {
+
+ pDeviceContext->RegistrationHandle = NULL;
+
+ KdPrint((" Create Device Object Failed with status= %X, num devices = %X\n",status,
+ NbtConfig.uNumDevices));
+
+ NbtLogEvent(EVENT_NBT_CREATE_DEVICE,status);
+ //
+ // this device will not be started so decrement the count of started
+ // ones.
+ //
+ NbtConfig.AdapterCount--;
+
+ //
+ // cleanup the mess and free the device object since we had some
+ // sort of failure.
+ //
+ pHead = &NbtConfig.DeviceContexts;
+ pEntry = RemoveTailList(pHead);
+
+ ASSERT (pDeviceContext == CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage));
+
+ if (pDeviceContext->hNameServer)
+ {
+ ObDereferenceObject(pDeviceContext->pNameServerFileObject);
+ Locstatus = NTZwCloseFile(pDeviceContext->hNameServer);
+ KdPrint(("Close NameSrv File status = %X\n",Locstatus));
+ }
+ if (pDeviceContext->hDgram)
+ {
+ ObDereferenceObject(pDeviceContext->pDgramFileObject);
+ Locstatus = NTZwCloseFile(pDeviceContext->hDgram);
+ KdPrint(("Close Dgram File status = %X\n",Locstatus));
+ }
+ if (pDeviceContext->hSession)
+ {
+ ObDereferenceObject(pDeviceContext->pSessionFileObject);
+ Locstatus = NTZwCloseFile(pDeviceContext->hSession);
+ KdPrint(("Close Session File status = %X\n",Locstatus));
+ }
+ if (pDeviceContext->hControl)
+ {
+ ObDereferenceObject(pDeviceContext->pControlFileObject);
+ Locstatus = NTZwCloseFile(pDeviceContext->hControl);
+ KdPrint(("Close Control File status = %X\n",Locstatus));
+ }
+
+ IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext);
+
+ }
+ else
+ {
+ //
+ // So we know that we need to register this device when an IP addres
+ // appears
+ //
+ pDeviceContext->RegistrationHandle = NULL;
+ DevicesStarted++;
+ pDeviceContext->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
+ }
+ }
+ }
+
+ }
+ //
+ // if no devices were created, then stop the timers and free the resources
+ //
+ if (DevicesStarted == 0)
+ {
+ ExDeleteResource(&NbtConfig.Resource);
+ StopInitTimers();
+ }
+ else
+ {
+ //
+ // at least one device context was created successfully, so return success
+ //
+ status = STATUS_SUCCESS;
+ }
+
+ if (NbtConfig.uNumDevices == 0)
+ {
+ NbtLogEvent(EVENT_NBT_NO_DEVICES,0);
+ }
+
+#endif // _PNP_POWER
+
+ if (pBindDevices)
+ {
+ CTEMemFree((PVOID)pBindDevices->RegistrySpace);
+ CTEMemFree((PVOID)pBindDevices);
+ }
+ if (pExportDevices)
+ {
+ CTEMemFree((PVOID)pExportDevices->RegistrySpace);
+ CTEMemFree((PVOID)pExportDevices);
+ }
+ if (pAddrArray)
+ {
+ CTEMemFree((PVOID)pAddrArray);
+ }
+
+#ifndef _PNP_LATER
+
+ //
+ // Get an Irp for the out of resource queue (used to disconnect sessions
+ // when really low on memory)
+ //
+ if (!IsListEmpty(&NbtConfig.DeviceContexts))
+ {
+ pEntry = NbtConfig.DeviceContexts.Flink;
+ pDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+
+ NbtConfig.OutOfRsrc.pIrp = NTAllocateNbtIrp(&pDeviceContext->DeviceObject);
+
+ if (!NbtConfig.OutOfRsrc.pIrp)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ //
+ // allocate a dpc structure and keep it: we might need if we hit an
+ // out-of-resource condition
+ //
+ NbtConfig.OutOfRsrc.pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('a'));
+ if (!NbtConfig.OutOfRsrc.pDpc)
+ {
+ IoFreeIrp(NbtConfig.OutOfRsrc.pIrp);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+#ifdef RASAUTODIAL
+ //
+ // Get the automatic connection driver
+ // entry points.
+ //
+ if (status == STATUS_SUCCESS)
+ {
+ NbtAcdBind();
+ }
+#endif
+
+#ifdef _PNP_POWER
+
+ (void)TdiRegisterAddressChangeHandler(
+ AddressArrival,
+ AddressDeletion,
+ &AddressChangeHandle
+ );
+
+#ifdef WATCHBIND
+ (void)TdiRegisterNotificationHandler(
+ BindHandler,
+ UnbindHandler,
+ &BindingHandle
+ );
+#endif // WATCHBIND
+
+#endif // _PNP_POWER
+ }
+ else
+ {
+ KdPrint(("NetBT!DriverEntry: Huh? Started NetBT with no devices!"));
+ }
+
+#endif // _PNP_POWER
+
+ NbtConfig.InterfaceIndex = 0;
+
+ //
+ // Return to the caller.
+ //
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtDispatchCleanup(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the NBT driver's dispatch function for IRP_MJ_CLEANUP
+ requests.
+
+ This function is called when the last reference to the handle is closed.
+ Hence, an NtClose() results in an IRP_MJ_CLEANUP first, and then an
+ IRP_MJ_CLOSE. This function runs down all activity on the object, and
+ when the close comes in the object is actually deleted.
+
+Arguments:
+
+ device - ptr to device object for target device
+ irp - ptr to I/O request packet
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpsp;
+ tDEVICECONTEXT *pDeviceContext;
+
+ CTEPagedCode();
+ pDeviceContext = (tDEVICECONTEXT *)Device;
+
+ irpsp = IoGetCurrentIrpStackLocation(irp);
+
+ // check that we got the correct major function code
+ ASSERT(irpsp->MajorFunction == IRP_MJ_CLEANUP);
+
+ // look at the context value that NBT put into the FSContext2 value to
+ // decide what to do
+ switch ((USHORT)irpsp->FileObject->FsContext2)
+ {
+ case NBT_ADDRESS_TYPE:
+ // the client is closing the address file, so we must cleanup
+ // and memory blocks associated with it.
+ status = NTCleanUpAddress(pDeviceContext,irp);
+ break;
+
+ case NBT_CONNECTION_TYPE:
+ // the client is closing a connection, so we must clean up any
+ // memory blocks associated with it.
+ status = NTCleanUpConnection(pDeviceContext,irp);
+ break;
+
+ case NBT_CONTROL_TYPE:
+ // there is nothing to do here....
+ status = STATUS_SUCCESS;
+ break;
+
+ default:
+ /*
+ * complete the i/o successfully.
+ */
+ status = STATUS_SUCCESS;
+ break;
+ }
+
+ //
+ // Complete the Irp
+ //
+ ReturnIrp(irp, status);
+ return(status);
+
+
+} // DispatchCleanup
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtDispatchClose(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP pIrp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the NBT driver's dispatch function for IRP_MJ_CLOSE
+ requests. This is called after Cleanup (above) is called.
+
+Arguments:
+
+ device - ptr to device object for target device
+ pIrp - ptr to I/O request packet
+
+Return Value:
+
+ an NT status code.
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpsp;
+ tDEVICECONTEXT *pDeviceContext;
+
+ CTEPagedCode();
+ pDeviceContext = (tDEVICECONTEXT *)Device;
+
+ //
+ // close operations are synchronous.
+ //
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+ pIrp->IoStatus.Information = 0;
+
+ irpsp = IoGetCurrentIrpStackLocation(pIrp);
+ ASSERT(irpsp->MajorFunction == IRP_MJ_CLOSE);
+
+ switch ((ULONG)irpsp->FileObject->FsContext2)
+ {
+ case NBT_ADDRESS_TYPE:
+ status = NTCloseAddress(pDeviceContext,pIrp);
+ break;
+
+ case NBT_CONNECTION_TYPE:
+ status = NTCloseConnection(pDeviceContext,pIrp);
+ break;
+
+ case NBT_WINS_TYPE:
+ status = NTCloseWinsAddr(pDeviceContext,pIrp);
+ break;
+
+ case NBT_CONTROL_TYPE:
+ // the client is closing the Control Object...
+ // there is nothing to do here....
+ status = STATUS_SUCCESS;
+ break;
+
+ default:
+ KdPrint(("Nbt:Close Received for unknown object type = %X\n",
+ irpsp->FileObject->FsContext2));
+ status = STATUS_SUCCESS;
+ break;
+ }
+
+ // NTCloseAddress can return Pending until the ref count actually gets
+ // to zero.
+ //
+ if (status != STATUS_PENDING)
+ {
+ ReturnIrp(pIrp, status);
+ }
+
+ return(status);
+
+} // DispatchClose
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtDispatchCreate(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP pIrp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the NBT driver's dispatch function for IRP_MJ_CREATE
+ requests. It is called as a consequence of one of the following:
+
+ a. TdiOpenConnection("\Device\Nbt_Elnkii0"),
+ b. TdiOpenAddress("\Device\Nbt_Elnkii0"),
+
+Arguments:
+
+ Device - ptr to device object being opened
+ pIrp - ptr to I/O request packet
+ pIrp->Status => return status
+ pIrp->MajorFunction => IRP_MD_CREATE
+ pIrp->MinorFunction => not used
+ pIpr->FileObject => ptr to file obj created by I/O system. NBT fills in FsContext
+ pIrp->AssociatedIrp.SystemBuffer => ptr to EA buffer with address of obj to open(Netbios Name)
+ pIrp->Parameters.Create.EaLength => length of buffer specifying the Xport Addr.
+
+Return Value:
+
+ STATUS_SUCCESS or STATUS_PENDING
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION pIrpsp;
+ PFILE_FULL_EA_INFORMATION ea;
+ tDEVICECONTEXT *pDeviceContext;
+ UCHAR IrpFlags;
+
+ CTEPagedCode();
+ pDeviceContext = (tDEVICECONTEXT *)Device;
+
+ //
+ // If this device was destroyed, then reject all opens on it.
+ // Ideally we would like the IO sub-system to guarantee that no
+ // requests come down on IoDeleted devices, but.....
+ //
+ if (InterlockedExchangeAdd(&pDeviceContext->IsDestroyed, 0) != 0) {
+ // IF_DBG(NBT_DEBUG_DRIVER)
+ KdPrint(("Nbt Rejecting Create minor Func\n"));
+
+ pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ pIrpsp = IoGetCurrentIrpStackLocation(pIrp);
+ ASSERT(pIrpsp->MajorFunction == IRP_MJ_CREATE);
+ IrpFlags = pIrpsp->Control;
+
+ //
+ // set the pending flag here so that it is sure to be set BEFORE the
+ // completion routine gets hit.
+ //
+ pIrp->IoStatus.Information = 0;
+ pIrp->IoStatus.Status = STATUS_PENDING;
+ IoMarkIrpPending(pIrp);
+
+ IF_DBG(NBT_DEBUG_DRIVER)
+ KdPrint(("Nbt Internal Ctrl minor Func = %X\n",pIrpsp->MinorFunction));
+
+ /*
+ * was this a TdiOpenConnection() or TdiOpenAddress()?
+ * Get the Extended Attribute pointer and look at the text
+ * value passed in for a match with "TransportAddress" or
+ * "ConnectionContext" (in FindEa)
+ */
+ ea = (PFILE_FULL_EA_INFORMATION) pIrp->AssociatedIrp.SystemBuffer;
+
+ if (!ea)
+ {
+ // a null ea means open the control object
+ status = NTOpenControl(pDeviceContext,pIrp);
+ }
+ else
+ if (FindInEA(ea, TdiConnectionContext))
+ {
+ // not allowed to pass in both a Connect Request and a Transport Address
+ ASSERT(!FindInEA(ea, TdiTransportAddress));
+ status = NTOpenConnection(pDeviceContext,pIrp);
+ }
+ else
+ if (FindInEA(ea, TdiTransportAddress))
+ {
+ status = NTOpenAddr(pDeviceContext,pIrp);
+ }
+ else
+ if (FindInEA(ea, WINS_INTERFACE_NAME))
+ {
+ status = NTOpenWinsAddr(pDeviceContext,pIrp);
+ }
+ else
+ {
+ status = STATUS_INVALID_EA_NAME;
+ pIrpsp->Control = IrpFlags;
+ ReturnIrp(pIrp, status);
+ return(status);
+ }
+
+ // complete the irp if the status is anything EXCEPT status_pending
+ // since the name query completion routine NTCompletIO completes pending
+ // open addresses
+
+ if (status != STATUS_PENDING)
+ {
+
+#if DBG
+ // *TODO* for debug...
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt: error return status = %X\n",status));
+ //ASSERTMSG("An error Status reported from NBT",0L);
+ }
+#endif
+
+ // reset the pending returned bit, since we are NOT returning pending
+ pIrpsp->Control = IrpFlags;
+
+ ReturnIrp(pIrp,status);
+
+ }
+
+
+ return(status);
+
+
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtDispatchDevCtrl(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the NBT driver's dispatch function for all
+ IRP_MJ_DEVICE_CONTROL requests.
+
+Arguments:
+
+ device - ptr to device object for target device
+ irp - ptr to I/O request packet
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpsp;
+ tDEVICECONTEXT *pDeviceContext;
+
+ CTEPagedCode();
+ pDeviceContext = (tDEVICECONTEXT *)Device;
+
+ irpsp = IoGetCurrentIrpStackLocation(irp);
+
+ //
+ // If this device was destroyed, then reject all requests on it.
+ // Ideally we would like the IO sub-system to guarantee that no
+ // requests come down on IoDeleted devices, but.....
+ //
+ if (InterlockedExchangeAdd(&pDeviceContext->IsDestroyed, 0) != 0) {
+ // IF_DBG(NBT_DEBUG_DRIVER)
+ KdPrint(("Nbt Rejecting Dev Ctrl code = %X\n",irpsp->Parameters.DeviceIoControl.IoControlCode));
+ irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ /*
+ * Initialize the I/O status block.
+ */
+ irp->IoStatus.Status = STATUS_PENDING;
+ irp->IoStatus.Information = 0;
+
+ ASSERT(irpsp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
+
+ IF_DBG(NBT_DEBUG_DRIVER)
+ KdPrint(("Nbt:DevCtrl hit with ControlCode == %X\n",
+ irpsp->Parameters.DeviceIoControl.IoControlCode));
+
+ if ((irpsp->Parameters.DeviceIoControl.IoControlCode >= IOCTL_NETBT_PURGE_CACHE) &&
+ (irpsp->Parameters.DeviceIoControl.IoControlCode <IOCTL_NETBT_LAST_IOCTL))
+ {
+ return(DispatchIoctls((tDEVICECONTEXT *)Device,irp, irpsp));
+ }
+ else
+ {
+ /*
+ * if possible, convert the (external) device control into internal
+ * format, then treat it as if it had arrived that way.
+ */
+ status = TdiMapUserRequest(Device, irp, irpsp);
+
+ if (status == STATUS_SUCCESS)
+ {
+ return(NbtDispatchInternalCtrl(Device, irp));
+ }
+ }
+
+ ReturnIrp(irp, STATUS_INVALID_DEVICE_REQUEST);
+ return(STATUS_INVALID_DEVICE_REQUEST);
+
+} // NbtDispatchDevCtrl
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtDispatchInternalCtrl(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP pIrp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the driver's dispatch function for all
+ IRP_MJ_INTERNAL_DEVICE_CONTROL requests.
+
+Arguments:
+
+ device - ptr to device object for target device
+ irp - ptr to I/O request packet
+
+Return Value:
+
+ NTSTATUS -- Indicates whether the request was successfully queued.
+
+--*/
+
+{
+ tDEVICECONTEXT *pDeviceContext;
+ PIO_STACK_LOCATION pIrpsp;
+ NTSTATUS status;
+ UCHAR IrpFlags;
+
+ pDeviceContext = (tDEVICECONTEXT *)Device;
+
+ pIrpsp = IoGetCurrentIrpStackLocation(pIrp);
+
+ //
+ // If this device was destroyed, then reject all operations on it.
+ // Ideally we would like the IO sub-system to guarantee that no
+ // requests come down on IoDeleted devices, but.....
+ //
+ if (InterlockedExchangeAdd(&pDeviceContext->IsDestroyed, 0) != 0) {
+ // IF_DBG(NBT_DEBUG_DRIVER)
+ KdPrint(("Nbt Rejecting Internal minor fn. = %X\n",pIrpsp->MinorFunction));
+ pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ /*
+ * Initialize the I/O status block.
+ */
+
+ //
+ // this check if first to optimize the Send path
+ //
+ if (pIrpsp->MinorFunction ==TDI_SEND)
+ {
+ //
+ // this routine decides if it should complete the irp or not
+ // It never returns status pending, so we can turn off the
+ // pending bit
+ //
+ return( NTSend(pDeviceContext,pIrp) );
+
+ }
+
+ IrpFlags = pIrpsp->Control;
+
+ ASSERT(pIrpsp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
+
+ IF_DBG(NBT_DEBUG_DRIVER)
+ KdPrint(("Nbt Internal Ctrl minor Func = %X\n",pIrpsp->MinorFunction));
+
+ switch (pIrpsp->MinorFunction)
+ {
+ case TDI_ACCEPT:
+ MakePending(pIrp);
+ status = NTAccept(pDeviceContext,pIrp);
+ break;
+
+ case TDI_ASSOCIATE_ADDRESS:
+ MakePending(pIrp);
+ status = NTAssocAddress(pDeviceContext,pIrp);
+ break;
+
+ case TDI_DISASSOCIATE_ADDRESS:
+ MakePending(pIrp);
+ status = NTDisAssociateAddress(pDeviceContext,pIrp);
+ break;
+
+ case TDI_CONNECT:
+ MakePending(pIrp);
+ status = NTConnect(pDeviceContext,pIrp);
+ break;
+
+ case TDI_DISCONNECT:
+ MakePending(pIrp);
+ status = NTDisconnect(pDeviceContext,pIrp);
+ break;
+
+ case TDI_LISTEN:
+ status = NTListen(pDeviceContext,pIrp);
+ return(status);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+ status = NTQueryInformation(pDeviceContext,pIrp);
+#if DBG
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt: Bad status from Query Info = %X\n",status));
+ }
+#endif
+ return(status);
+ break;
+
+ case TDI_RECEIVE:
+ status = NTReceive(pDeviceContext,pIrp);
+ return(status);
+
+ break;
+
+ case TDI_RECEIVE_DATAGRAM:
+ status = NTReceiveDatagram(pDeviceContext,pIrp);
+ return(status);
+ break;
+
+
+ case TDI_SEND_DATAGRAM:
+
+ status = NTSendDatagram(pDeviceContext,pIrp);
+#if DBG
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt: Bad status from Dgram Send = %X\n",status));
+ }
+#endif
+ return(status);
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+ MakePending(pIrp);
+ status = NTSetEventHandler(pDeviceContext,pIrp);
+ break;
+
+ case TDI_SET_INFORMATION:
+ MakePending(pIrp);
+ status = NTSetInformation(pDeviceContext,pIrp);
+ break;
+
+ #if DBG
+ //
+ // 0x7f is a request by the redirector to put a "magic bullet" out on
+ // the wire, to trigger the Network General Sniffer.
+ //
+ case 0x7f:
+ KdPrint(("NBT:DispatchInternalCtrl - 07f minor function code\n"));
+ ReturnIrp(pIrp, STATUS_NOT_SUPPORTED);
+ return(STATUS_NOT_SUPPORTED);
+
+ #endif /* DBG */
+
+ default:
+ KdPrint(("NBT:Dispatch Internal Ctl - invalid minor function %X\n",
+ pIrpsp->MinorFunction));
+ ReturnIrp(pIrp, STATUS_INVALID_DEVICE_REQUEST);
+ return(STATUS_INVALID_DEVICE_REQUEST);
+ }
+
+ // if the returned status is pending, then we do not complete the IRP
+ // here since it will be completed elsewhere in the code...
+ //
+ if (status != STATUS_PENDING)
+ {
+#if DBG
+ // *TODO* for debug...
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("NBT:error return status = %X,MinorFunc = %X\n",status,pIrpsp->MinorFunction));
+// ASSERTMSG("An error Status reported from NBT",0L);
+ }
+
+#endif
+ pIrpsp->Control = IrpFlags;
+
+ ReturnIrp(pIrp,status);
+
+ }
+
+ return(status);
+
+
+} // NbtDispatchInternalCtrl
+
+
+//----------------------------------------------------------------------------
+ PFILE_FULL_EA_INFORMATION
+FindInEA(
+ IN PFILE_FULL_EA_INFORMATION start,
+ IN PCHAR wanted
+ )
+
+/*++
+
+Routine Description:
+
+ This function check for the "Wanted" string in the Ea structure and
+ returns a pointer to the extended attribute structure
+ representing the given extended attribute name.
+
+Arguments:
+
+ device - ptr to device object for target device
+ pIrp - ptr to I/O request packet
+
+Return Value:
+
+ pointer to the extended attribute structure, or NULL if not found.
+
+--*/
+
+{
+ PFILE_FULL_EA_INFORMATION eabuf;
+
+ CTEPagedCode();
+
+ for (eabuf = start; eabuf; eabuf += eabuf->NextEntryOffset)
+ {
+
+ if (strncmp(eabuf->EaName,wanted,eabuf->EaNameLength) == 0)
+ {
+ return eabuf;
+ }
+
+ if (eabuf->NextEntryOffset == 0)
+ {
+ return((PFILE_FULL_EA_INFORMATION) NULL);
+ }
+
+ }
+ return((PFILE_FULL_EA_INFORMATION) NULL);
+
+} // FindEA
+
+
+
+//----------------------------------------------------------------------------
+ VOID
+ReturnIrp(
+ IN PIRP pIrp,
+ IN int status
+ )
+
+/*++
+
+Routine Description:
+
+ This function completes an IRP, and arranges for return parameters,
+ if any, to be copied.
+
+ Although somewhat a misnomer, this function is named after a similar
+ function in the SpiderSTREAMS emulator.
+
+Arguments:
+
+ pIrp - pointer to the IRP to complete
+ status - completion status of the IRP
+
+Return Value:
+
+ number of bytes copied back to the user.
+
+--*/
+
+{
+ KIRQL oldlevel;
+ CCHAR priboost;
+
+ //
+ // pIrp->IoStatus.Information is meaningful only for STATUS_SUCCESS
+ //
+
+ // set the Irps cancel routine to null or the system may bugcheck
+ // with a bug code of CANCEL_STATE_IN_COMPLETED_IRP
+ //
+ // refer to IoCancelIrp() ..\ntos\io\iosubs.c
+ //
+ IoAcquireCancelSpinLock(&oldlevel);
+ IoSetCancelRoutine(pIrp,NULL);
+ IoReleaseCancelSpinLock(oldlevel);
+
+ pIrp->IoStatus.Status = status;
+
+ priboost = (CCHAR) ((status == STATUS_SUCCESS) ?
+ IO_NETWORK_INCREMENT : IO_NO_INCREMENT);
+
+ IoCompleteRequest(pIrp, priboost);
+
+ return;
+
+}
+//----------------------------------------------------------------------------
+ VOID
+MakePending(
+ IN PIRP pIrp
+ )
+
+/*++
+
+Routine Description:
+
+ This function marks an irp pending and sets the correct status.
+
+Arguments:
+
+ pIrp - pointer to the IRP to complete
+ status - completion status of the IRP
+
+Return Value:
+
+
+--*/
+
+{
+ IoMarkIrpPending(pIrp);
+ pIrp->IoStatus.Status = STATUS_PENDING;
+ pIrp->IoStatus.Information = 0;
+
+}
+
diff --git a/private/ntos/nbt/nt/fileio.c b/private/ntos/nbt/nt/fileio.c
new file mode 100644
index 000000000..5490c3acd
--- /dev/null
+++ b/private/ntos/nbt/nt/fileio.c
@@ -0,0 +1,384 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fileio.c
+
+Abstract:
+
+ This source implements a stdio-like facility.
+
+Author:
+
+ Jim Stewart June 1993
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+#include "hosts.h"
+#include <string.h>
+
+
+//
+// Private Definitions
+//
+
+
+
+//
+// Local Variables
+//
+
+
+
+//
+// Local (Private) Functions
+//
+PUCHAR
+LmpMapFile (
+ IN HANDLE handle,
+ IN OUT int *pnbytes
+ );
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, LmCloseFile)
+#pragma CTEMakePageable(PAGE, LmFgets)
+#pragma CTEMakePageable(PAGE, LmpMapFile)
+#pragma CTEMakePageable(PAGE, LmOpenFile)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//----------------------------------------------------------------------------
+
+NTSTATUS
+LmCloseFile (
+ IN PLM_FILE pfile
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes a file opened via LmOpenFile(), and frees its
+ LM_FILE object.
+
+Arguments:
+
+ pfile - pointer to the LM_FILE object
+
+Return Value:
+
+ An NTSTATUS value.
+
+--*/
+
+
+{
+ NTSTATUS status;
+
+ CTEPagedCode();
+ CTEMemFree(pfile->f_buffer);
+
+ status = ZwClose(pfile->f_handle);
+
+ ASSERT(status == STATUS_SUCCESS);
+
+ CTEMemFree(pfile);
+
+ return(status);
+
+} // LmCloseFile
+
+
+
+//----------------------------------------------------------------------------
+
+PUCHAR
+LmFgets (
+ IN PLM_FILE pfile,
+ OUT int *nbytes
+ )
+
+/*++
+
+Routine Description:
+
+ This function is vaguely similar to fgets(3).
+
+ Starting at the current seek position, it reads through a newline
+ character, or the end of the file. If a newline is encountered, it
+ is replaced with a NULL character.
+
+Arguments:
+
+ pfile - file to read from
+ nbytes - the number of characters read, excluding the NULL character
+
+Return Value:
+
+ A pointer to the beginning of the line, or NULL if we are at or past
+ the end of the file.
+
+--*/
+
+
+{
+ PUCHAR endOfLine;
+ PUCHAR startOfLine;
+ size_t maxBytes;
+
+ CTEPagedCode();
+ startOfLine = pfile->f_current;
+
+ if (startOfLine >= pfile->f_limit)
+ {
+
+ return((PUCHAR) NULL);
+ }
+
+ maxBytes = pfile->f_limit - pfile->f_current;
+ endOfLine = (PUCHAR) memchr(startOfLine, (UCHAR) '\n', maxBytes);
+
+ if (!endOfLine)
+ {
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("NBT: lmhosts file doesn't end in '\\n'"));
+ endOfLine = pfile->f_limit;
+ }
+
+ *endOfLine = (UCHAR) NULL;
+
+ pfile->f_current = endOfLine + 1;
+ (pfile->f_lineno)++;
+ ASSERT(pfile->f_current <= pfile->f_limit+1);
+
+ *nbytes = endOfLine - startOfLine;
+
+ return(startOfLine);
+
+} // LmFgets
+
+
+
+//----------------------------------------------------------------------------
+
+PUCHAR
+LmpMapFile (
+ IN HANDLE handle,
+ IN OUT int *pnbytes
+ )
+
+/*++
+
+Routine Description:
+
+ This function reads an entire file into memory.
+
+Arguments:
+
+ handle - file handle
+ pnbytes - size of the whole file
+
+
+Return Value:
+
+ the buffer allocated, or NULL if unsuccessful.
+
+--*/
+
+
+{
+ PUCHAR buffer;
+ NTSTATUS status;
+ IO_STATUS_BLOCK iostatus;
+ FILE_STANDARD_INFORMATION stdInfo;
+ LARGE_INTEGER offset ={0, 0};
+ LARGE_INTEGER length ={0x7fffffff, 0x7fffffff};
+
+ CTEPagedCode();
+
+
+ status = ZwQueryInformationFile(
+ handle, // FileHandle
+ &iostatus, // IoStatusBlock
+ (PVOID) &stdInfo, // FileInformation
+ sizeof(stdInfo), // Length
+ FileStandardInformation); // FileInformationClass
+
+ if (status != STATUS_SUCCESS)
+ {
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("NBT: ZwQueryInformationFile(std) = %X\n", status));
+ return(NULL);
+ }
+
+ length = stdInfo.EndOfFile; // structure copy
+
+ if (length.HighPart)
+ {
+ return(NULL);
+ }
+
+ buffer = ExAllocatePool(NonPagedPool, length.LowPart+2);
+
+ if (buffer != NULL)
+ {
+
+ status = ZwReadFile(
+ handle, // FileHandle
+ NULL, // Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &iostatus, // IoStatusBlock
+ buffer, // Buffer
+ length.LowPart, // Length
+ &offset, // ByteOffset
+ NULL); // Key
+
+ if (status != STATUS_SUCCESS)
+ {
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("NBT: ZwReadFile(std) = %X\n", status));
+ }
+
+ ASSERT(status != STATUS_PENDING);
+
+ if (iostatus.Status != STATUS_SUCCESS || status != STATUS_SUCCESS)
+ {
+ CTEMemFree(buffer);
+ return(NULL);
+ }
+
+ *pnbytes = length.LowPart;
+ }
+ return(buffer);
+
+} // LmpMapFile
+
+
+
+//----------------------------------------------------------------------------
+
+PLM_FILE
+LmOpenFile (
+ IN PUCHAR path
+ )
+
+/*++
+
+Routine Description:
+
+ This function opens a file for use by LmFgets().
+
+Arguments:
+
+ path - a fully specified, complete path to the file.
+
+Return Value:
+
+ A pointer to an LM_FILE object, or NULL if unsuccessful.
+
+--*/
+
+
+{
+ NTSTATUS status;
+ HANDLE handle;
+ PLM_FILE pfile;
+ IO_STATUS_BLOCK iostatus;
+ OBJECT_ATTRIBUTES attributes;
+ UNICODE_STRING ucPath;
+ PUCHAR start;
+ int nbytes;
+ OEM_STRING String;
+ PUCHAR LongerPath;
+
+
+ CTEPagedCode();
+ ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
+
+ status = LmGetFullPath(path,&LongerPath);
+
+ if (NT_SUCCESS(status))
+ {
+ RtlInitString(&String,LongerPath);
+
+ status = RtlAnsiStringToUnicodeString(&ucPath,&String,TRUE);
+
+ if (NT_SUCCESS(status))
+ {
+
+ InitializeObjectAttributes(
+ &attributes, // POBJECT_ATTRIBUTES
+ &ucPath, // ObjectName
+ OBJ_CASE_INSENSITIVE, // Attributes
+ (HANDLE) NULL, // RootDirectory
+ (PSECURITY_DESCRIPTOR) NULL); // SecurityDescriptor
+
+ status = ZwCreateFile(
+ &handle, // FileHandle
+ SYNCHRONIZE | FILE_READ_DATA, // DesiredAccess
+ &attributes, // ObjectAttributes
+ &iostatus, // IoStatusBlock
+ 0, // AllocationSize
+ FILE_ATTRIBUTE_NORMAL, // FileAttributes
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // ShareAccess
+ FILE_OPEN, // CreateDisposition
+ FILE_SYNCHRONOUS_IO_NONALERT, // OpenOptions
+ NULL, // EaBuffer
+ 0); // EaLength
+
+ if (NT_SUCCESS(status))
+ {
+ start = LmpMapFile(handle, &nbytes);
+
+ if (start)
+ {
+ pfile = (PLM_FILE) ExAllocatePool(NonPagedPool, sizeof(LM_FILE));
+
+ if (pfile)
+ {
+ KeInitializeSpinLock(&(pfile->f_lock));
+
+ pfile->f_refcount = 1;
+ pfile->f_handle = handle;
+ pfile->f_lineno = 0;
+ pfile->f_fileOffset.HighPart = 0;
+ pfile->f_fileOffset.LowPart = 0;
+
+ pfile->f_current = start;
+ pfile->f_buffer = start;
+ pfile->f_limit = pfile->f_buffer + nbytes;
+
+ RtlFreeUnicodeString(&ucPath);
+ CTEMemFree(LongerPath);
+
+ return(pfile);
+ }
+
+ CTEMemFree(start);
+ }
+
+ ZwClose(handle);
+ }
+
+ RtlFreeUnicodeString(&ucPath);
+
+ IF_DBG(NBT_DEBUG_LMHOST)
+ KdPrint(("NBT: ZwOpenFile(std) = %X\n", status));
+
+ }
+
+ CTEMemFree(LongerPath);
+ }
+
+ return((PLM_FILE) NULL);
+
+} // LmOpenFile
+
+
diff --git a/private/ntos/nbt/nt/mp/makefile b/private/ntos/nbt/nt/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/nbt/nt/mp/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/nbt/nt/mp/netbt.prf b/private/ntos/nbt/nt/mp/netbt.prf
new file mode 100644
index 000000000..84914dcb9
--- /dev/null
+++ b/private/ntos/nbt/nt/mp/netbt.prf
@@ -0,0 +1,170 @@
+SendCompletion@12
+NbtDispatchInternalCtrl@8
+NTSend@8
+TdiReceiveHandler@32
+CompletionRcv@12
+ProcessIrp@24
+CTECountedAllocMem@8
+DgramHndlrNotOs@48
+ConvertToAscii@20
+UdpSendDatagram@28
+NbtDereferenceClient@4
+NTIoComplete@12
+MakeRemoteAddressStructure@16
+FindName@16
+GetIrp@4
+TdiSendDatagram@24
+DgramSendComplete@12
+FindInHashTable@16
+SendDgramCompletion@12
+CTECountedFreeMem@8
+DgramSendCleanupTracker@12
+NbtDereferenceName@4
+TdiRcvDatagramHandler@44
+GetNetBiosNameFromTransportAddress@12
+FindNameOrQuery@28
+NbtAllocTracker@0
+NbtDereferenceAddress@4
+NTSendDatagram@8
+NbtSendDatagram@28
+SendDgram@8
+ConvertToHalfAscii@16
+BuildSendDgramHdr@32
+RemoteHashTimeout@12
+TimerExpiry@16
+CTEStartTimer@16
+NTQueryInformation@8
+NTOpenConnection@8
+CreateDeviceString@8
+FreeTracker@8
+GetTracker@4
+SubmitTdiRequest@8
+TdiRcvNameSrvHandler@44
+GetEntry@12
+UdpSendNSBcast@36
+NDgramSendCompleted@12
+CreatePdu@32
+FindInEA@8
+MSnodeCompletion@12
+NbtOpenAndAssocConnection@8
+SrcIsUs@4
+AddToPendingList@8
+QueryNameOnNet@44
+NbtTdiAssociateConnection@8
+CompleteClientReq@12
+ClearCancelRoutine@4
+StartTimer@32
+StartLmHostTimer@8
+LmHostQueueRequest@16
+GetNameToFind@4
+RemoveNameAndCompleteReq@8
+RemoveName@4
+NameSrvHndlrNotOs@16
+ReturnIrp@8
+CheckRegistrationFromNet@16
+DereferenceTracker@4
+CTEInitTimer@4
+TimeoutQEntries@12
+LmHostTimeout@12
+GetContext@4
+MakePending@4
+FindNameRemoteThenLocal@8
+NbtOpenConnection@12
+NbtTdiOpenConnection@8
+NbtDispatchCreate@8
+SendDgramContinue@8
+CompletionRoutine@12
+AllocateMdl@4
+NTAssocAddress@8
+NbtAssociateAddress@12
+NTAllocateNbtIrp@4
+NbtGetMdl@8
+NbtListen@20
+NbtAllocateClientBlock@4
+NbtSetEventHandler@16
+InterlockedCallCompletion@8
+NTSetEventHandler@8
+FindInDomainList@8
+NbtRegisterName@32
+NTCheckSetCancelRoutine@12
+InitTimerQ@4
+CountLocalNames@4
+NbtInitConnQ@16
+AddToHashTable@28
+NbtInitTrackerQ@8
+NbtAppendString@12
+NbtQueryAdapterStatus@12
+QueryProviderCompletion@12
+NbtAddPermanentName@4
+ReadParameters2@8
+IncrementNameStats@8
+MSnodeRegCompletion@12
+NbtRegisterCompletion@8
+NbtOpenAddress@24
+InitQ@12
+NTSetFileObjectContexts@12
+NbtCreateDeviceObject@24
+CreateHashTable@12
+InitNotOs@0
+InitTimersNotOs@0
+TcpSendSessionResponse@12
+TcpSendSession@12
+Inbound@32
+CompleteSessionSetup@20
+SessionRespDone@12
+UdpSendResponse@32
+QueryRespDone@12
+SrcIsNameServer@8
+QueryFromNet@20
+NbtDispatchCleanup@8
+ConvertDottedDecimalToUlong@8
+NTGetLmHostPath@4
+NbtDispatchClose@8
+NbtDispatchDevCtrl@8
+NTOpenControl@8
+NbtCreateAddressObjects@12
+NTSetSharedAccess@12
+FindSessionEndPoint@24
+DispatchIoctls@12
+ReadParameters@8
+NTListen@8
+ConvertToUlong@8
+NbtInitMdlQ@8
+GetExtendedAttributes@4
+ReadNameServerAddresses@16
+GetServerAddress@12
+NbtReadRegistry@24
+GetIPFromRegistry@16
+NbtReadLinkageInformation@16
+NTReadIniString@12
+ReadElement@12
+NbtReadSingleParameter@16
+NbtOpenRegistry@12
+NbtFindLastSlash@12
+ReadStringRelative@16
+OpenAndReadElement@12
+SetEventHandler@20
+NbtTdiOpenAddress@28
+NbtTdiOpenControl@4
+SetWinsDownFlag@4
+LmGetFullPath@8
+TdiConnectHandler@36
+NTOpenAddr@8
+AcceptCompletionRoutine@12
+NTCheckSharedAccess@12
+LmOpenFile@4
+LmpBreakRecursion@8
+SendSessionCompletionRoutine@12
+ScanLmHostFile@4
+TdiSend@24
+NTReceive@8
+ClientTookSomeOfTheData@20
+LmGetIpAddr@16
+ConnectHndlrNotOs@24
+NTProcessAcceptIrp@8
+InitRemoteHashTable@12
+DriverEntry@8
+ReadLmHostFile@8
+ReadScope@8
+ClearConnStructures@8
+NbtQueryConnectionList@12
diff --git a/private/ntos/nbt/nt/mp/sources b/private/ntos/nbt/nt/mp/sources
new file mode 100644
index 000000000..33e022722
--- /dev/null
+++ b/private/ntos/nbt/nt/mp/sources
@@ -0,0 +1,30 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+TARGETLIBS=..\..\nbt\mp\obj\*\nbt.lib
+
+!include ..\sources.inc
diff --git a/private/ntos/nbt/nt/netbt.rc b/private/ntos/nbt/nt/netbt.rc
new file mode 100644
index 000000000..198701954
--- /dev/null
+++ b/private/ntos/nbt/nt/netbt.rc
@@ -0,0 +1,13 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "MBT Transport driver"
+
+#define VER_INTERNALNAME_STR "netbt.sys"
+#define VER_ORIGINALFILENAME_STR "netbt.sys"
+
+#include <common.ver>
+
diff --git a/private/ntos/nbt/nt/netbtkd/kdextlib.c b/private/ntos/nbt/nt/netbtkd/kdextlib.c
new file mode 100644
index 000000000..132d57b5d
--- /dev/null
+++ b/private/ntos/nbt/nt/netbtkd/kdextlib.c
@@ -0,0 +1,843 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ kdextlib.c
+
+Abstract:
+
+ Library routines for dumping data structures given a meta level descrioption
+
+Author:
+
+ Balan Sethu Raman (SethuR) 11-May-1994
+
+Notes:
+ The implementation tends to avoid memory allocation and deallocation as much as possible.
+ Therefore We have choosen an arbitrary length as the default buffer size. A mechanism will
+ be provided to modify this buffer length through the debugger extension commands.
+
+Revision History:
+
+ 11-Nov-1994 SethuR Created
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include "ntverp.h"
+
+#define KDEXTMODE
+
+#include <windef.h>
+#include <ntkdexts.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <kdextlib.h>
+
+PNTKD_OUTPUT_ROUTINE lpOutputRoutine;
+PNTKD_GET_EXPRESSION lpGetExpressionRoutine;
+PNTKD_GET_SYMBOL lpGetSymbolRoutine;
+PNTKD_READ_VIRTUAL_MEMORY lpReadMemoryRoutine;
+
+#define PRINTF lpOutputRoutine
+#define ERROR lpOutputRoutine
+
+#define NL 1
+#define NONL 0
+
+#define SETCALLBACKS() \
+ lpOutputRoutine = lpExtensionApis->lpOutputRoutine; \
+ lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine; \
+ lpGetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine; \
+ lpReadMemoryRoutine = lpExtensionApis->lpReadVirtualMemRoutine;
+
+#define DEFAULT_UNICODE_DATA_LENGTH 512
+USHORT s_UnicodeStringDataLength = DEFAULT_UNICODE_DATA_LENGTH;
+WCHAR s_UnicodeStringData[DEFAULT_UNICODE_DATA_LENGTH];
+WCHAR *s_pUnicodeStringData = s_UnicodeStringData;
+
+#define DEFAULT_ANSI_DATA_LENGTH 512
+USHORT s_AnsiStringDataLength = DEFAULT_ANSI_DATA_LENGTH;
+CHAR s_AnsiStringData[DEFAULT_ANSI_DATA_LENGTH];
+CHAR *s_pAnsiStringData = s_AnsiStringData;
+
+//
+// No. of columns used to display struct fields;
+//
+
+ULONG s_MaxNoOfColumns = 3;
+ULONG s_NoOfColumns = 1;
+
+/*
+ * Fetches the data at the given address
+ */
+BOOLEAN
+GetData( DWORD dwAddress, PVOID ptr, ULONG size)
+{
+ BOOL b;
+ ULONG BytesRead;
+
+ b = (lpReadMemoryRoutine)((LPVOID) dwAddress, ptr, size, &BytesRead );
+
+
+ if (!b || BytesRead != size ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Fetch the null terminated ASCII string at dwAddress into buf
+ */
+BOOL
+GetString( DWORD dwAddress, PSZ buf )
+{
+ do {
+ if( !GetData( dwAddress,buf, 1) )
+ return FALSE;
+
+ dwAddress++;
+ buf++;
+
+ } while( *buf != '\0' );
+
+ return TRUE;
+}
+
+/*
+ * Displays a byte in hexadecimal
+ */
+VOID
+PrintHexChar( UCHAR c )
+{
+ PRINTF( "%c%c", "0123456789abcdef"[ (c>>4)&7 ], "0123456789abcdef"[ c&7 ] );
+}
+
+/*
+ * Displays a buffer of data in hexadecimal
+ */
+VOID
+PrintHexBuf( PUCHAR buf, ULONG cbuf )
+{
+ while( cbuf-- ) {
+ PrintHexChar( *buf++ );
+ PRINTF( " " );
+ }
+}
+
+/*
+ * Displays a unicode string
+ */
+BOOL
+PrintStringW(LPSTR msg, PUNICODE_STRING puStr, BOOL nl )
+{
+ UNICODE_STRING UnicodeString;
+ ANSI_STRING AnsiString;
+ BOOLEAN b;
+
+ if( msg )
+ PRINTF( msg );
+
+ if( puStr->Length == 0 ) {
+ if( nl )
+ PRINTF( "\n" );
+ return TRUE;
+ }
+
+ UnicodeString.Buffer = s_pUnicodeStringData;
+ UnicodeString.MaximumLength = s_UnicodeStringDataLength;
+ UnicodeString.Length = (puStr->Length > s_UnicodeStringDataLength)
+ ? s_UnicodeStringDataLength
+ : puStr->Length;
+
+ b = (lpReadMemoryRoutine)(
+ (LPVOID) puStr->Buffer,
+ UnicodeString.Buffer,
+ UnicodeString.Length,
+ NULL);
+
+ if (b) {
+ RtlUnicodeStringToAnsiString(&AnsiString, puStr, TRUE);
+ PRINTF("%s%s", AnsiString.Buffer, nl ? "\n" : "" );
+ RtlFreeAnsiString(&AnsiString);
+ }
+
+ return b;
+}
+
+/*
+ * Displays a ANSI string
+ */
+BOOL
+PrintStringA(LPSTR msg, PANSI_STRING pStr, BOOL nl )
+{
+ ANSI_STRING AnsiString;
+ BOOLEAN b;
+
+ if( msg )
+ PRINTF( msg );
+
+ if( pStr->Length == 0 ) {
+ if( nl )
+ PRINTF( "\n" );
+ return TRUE;
+ }
+
+ AnsiString.Buffer = s_pAnsiStringData;
+ AnsiString.MaximumLength = s_AnsiStringDataLength;
+ AnsiString.Length = (pStr->Length > (s_AnsiStringDataLength - 1))
+ ? (s_AnsiStringDataLength - 1)
+ : pStr->Length;
+
+ b = (lpReadMemoryRoutine)(
+ (LPVOID) pStr->Buffer,
+ AnsiString.Buffer,
+ AnsiString.Length,
+ NULL);
+
+ if (b) {
+ AnsiString.Buffer[ AnsiString.Length ] = '\0';
+ PRINTF("%s%s", AnsiString.Buffer, nl ? "\n" : "" );
+ }
+
+ return b;
+}
+
+/*
+ * Displays all the fields of a given struct. This is the driver routine that is called
+ * with the appropriate descriptor array to display all the fields in a given struct.
+ */
+
+char *NewLine = "\n";
+char *FieldSeparator = " ";
+char *DotSeparator = ".";
+#define NewLineForFields(FieldNo) \
+ ((((FieldNo) % s_NoOfColumns) == 0) ? NewLine : FieldSeparator)
+#define FIELD_NAME_LENGTH 30
+
+VOID
+PrintStructFields( DWORD dwAddress, VOID *ptr, FIELD_DESCRIPTOR *pFieldDescriptors )
+{
+ int i;
+ int j;
+ BYTE ch;
+
+ // Display the fields in the struct.
+ for( i=0; pFieldDescriptors->Name; i++, pFieldDescriptors++ ) {
+
+ // Indentation to begin the struct display.
+ PRINTF( " " );
+
+ if( strlen( pFieldDescriptors->Name ) > FIELD_NAME_LENGTH ) {
+ PRINTF( "%-17s...%s ", pFieldDescriptors->Name, pFieldDescriptors->Name+strlen(pFieldDescriptors->Name)-10 );
+ } else {
+ PRINTF( "%-30s ", pFieldDescriptors->Name );
+ }
+
+ PRINTF( "(0x%-2X) ", pFieldDescriptors->Offset );
+
+ switch( pFieldDescriptors->FieldType ) {
+ case FieldTypeByte:
+ case FieldTypeChar:
+ PRINTF( "%-16d%s",
+ *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ),
+ NewLineForFields(i) );
+ break;
+
+ case FieldTypeBoolean:
+ PRINTF( "%-16s%s",
+ *(BOOLEAN *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE",
+ NewLineForFields(i));
+ break;
+
+ case FieldTypeBool:
+ PRINTF( "%-16s%s",
+ *(BOOLEAN *)(((char *)ptr) + pFieldDescriptors->Offset ) ? "TRUE" : "FALSE",
+ NewLineForFields(i));
+ break;
+
+ case FieldTypePointer:
+ PRINTF( "%-16X%s",
+ *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
+ NewLineForFields(i) );
+ break;
+
+ case FieldTypeULongULong:
+ PRINTF( "%d%s",
+ *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
+ FieldSeparator );
+ PRINTF( "%d%s",
+ *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset + sizeof(ULONG)),
+ NewLineForFields(i) );
+ break;
+
+ case FieldTypeListEntry:
+
+ if ( (ULONG)(dwAddress + pFieldDescriptors->Offset) ==
+ *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ))
+ {
+ PRINTF( "%s", "List Empty\n" );
+ }
+ else
+ {
+ PRINTF( "%-8X%s",
+ *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
+ FieldSeparator );
+ PRINTF( "%-8X%s",
+ *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset + sizeof(ULONG)),
+ NewLineForFields(i) );
+ }
+ break;
+
+ // Ip address: 4 bytes long
+ case FieldTypeIpAddr:
+ PRINTF( "%X%s",
+ *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
+ FieldSeparator );
+ PRINTF( "(%d%s",
+ *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 3),
+ DotSeparator );
+ PRINTF( "%d%s",
+ *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 2 ),
+ DotSeparator );
+ PRINTF( "%d%s",
+ *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 1 ),
+ DotSeparator );
+ PRINTF( "%d)%s",
+ *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset ),
+ NewLineForFields(i) );
+ break;
+
+ // Mac address: 6 bytes long
+ case FieldTypeMacAddr:
+ for (j=0; j<5; j++)
+ {
+ PRINTF( "%X%s",
+ *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j),
+ FieldSeparator );
+ }
+ PRINTF( "%X%s",
+ *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 5),
+ NewLineForFields(i) );
+ break;
+
+ // Netbios name: 16 bytes long
+ case FieldTypeNBName:
+ //
+ // if first byte is printable, print the first 15 bytes as characters
+ // and 16th byte as a hex value. otherwise, print all the 16 bytes
+ // as hex values
+ //
+ ch = *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset);
+ if (ch >= 0x20 && ch <= 0x7e)
+ {
+ for (j=0; j<15; j++)
+ {
+ PRINTF( "%c", *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j));
+ }
+ PRINTF( "<%X>%s",
+ *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + 15),
+ NewLineForFields(i) );
+ }
+ else
+ {
+ for (j=0; j<16; j++)
+ {
+ PRINTF( "%.2X",
+ *(BYTE *)(((char *)ptr) + pFieldDescriptors->Offset + j));
+ }
+ PRINTF( "%s", NewLineForFields(i) );
+ }
+ break;
+
+ case FieldTypeULong:
+ case FieldTypeLong:
+ PRINTF( "%-16d%s",
+ *(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ),
+ NewLineForFields(i) );
+ break;
+
+ case FieldTypeShort:
+ PRINTF( "%-16X%s",
+ *(SHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
+ NewLineForFields(i) );
+ break;
+
+ case FieldTypeUShort:
+ PRINTF( "%-16X%s",
+ *(USHORT *)(((char *)ptr) + pFieldDescriptors->Offset ),
+ NewLineForFields(i) );
+ break;
+
+ case FieldTypeUnicodeString:
+ PrintStringW( NULL, (UNICODE_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL );
+ PRINTF( NewLine );
+ break;
+
+ case FieldTypeAnsiString:
+ PrintStringA( NULL, (ANSI_STRING *)(((char *)ptr) + pFieldDescriptors->Offset ), NONL );
+ PRINTF( NewLine );
+ break;
+
+ case FieldTypeSymbol:
+ {
+ UCHAR SymbolName[ 200 ];
+ ULONG Displacement;
+ PVOID sym = (PVOID)(*(ULONG *)(((char *)ptr) + pFieldDescriptors->Offset ));
+
+ lpGetSymbolRoutine( sym, SymbolName, &Displacement );
+ PRINTF( "%-16s%s",
+ SymbolName,
+ NewLineForFields(i) );
+ }
+ break;
+
+ case FieldTypeEnum:
+ {
+ ULONG EnumValue;
+ ENUM_VALUE_DESCRIPTOR *pEnumValueDescr;
+ // Get the associated numericla value.
+
+ EnumValue = *((ULONG *)((BYTE *)ptr + pFieldDescriptors->Offset));
+
+ if ((pEnumValueDescr = pFieldDescriptors->AuxillaryInfo.pEnumValueDescriptor)
+ != NULL) {
+ //
+ // An auxilary textual description of the value is
+ // available. Display it instead of the numerical value.
+ //
+
+ LPSTR pEnumName = NULL;
+
+ while (pEnumValueDescr->EnumName != NULL) {
+ if (EnumValue == pEnumValueDescr->EnumValue) {
+ pEnumName = pEnumValueDescr->EnumName;
+ break;
+ }
+ }
+
+ if (pEnumName != NULL) {
+ PRINTF( "%-16s ", pEnumName );
+ } else {
+ PRINTF( "%-4d (%-10s) ", EnumValue,"@$#%^&*");
+ }
+
+ } else {
+ //
+ // No auxilary information is associated with the ehumerated type
+ // print the numerical value.
+ //
+ PRINTF( "%-16d",EnumValue);
+ }
+ }
+ break;
+
+ case FieldTypeStruct:
+ PRINTF( "@%-15X%s",
+ (dwAddress + pFieldDescriptors->Offset ),
+ NewLineForFields(i) );
+ break;
+
+ case FieldTypeLargeInteger:
+ case FieldTypeFileTime:
+ default:
+ ERROR( "Unrecognized field type %c for %s\n", pFieldDescriptors->FieldType, pFieldDescriptors->Name );
+ break;
+ }
+ }
+}
+
+LPSTR LibCommands[] = {
+ "dump <Struct Type Name>@<address expr> ",
+ "columns <d> -- controls the number of columns in the display ",
+ "logdump <Log Address> ",
+ 0
+};
+
+BOOL
+help(
+ DWORD dwCurrentPC,
+ PNTKD_EXTENSION_APIS lpExtensionApis,
+ LPSTR lpArgumentString
+)
+{
+ int i;
+
+ SETCALLBACKS();
+
+ for( i=0; Extensions[i]; i++ )
+ PRINTF( " %s\n", Extensions[i] );
+
+ for( i=0; LibCommands[i]; i++ )
+ PRINTF( " %s\n", LibCommands[i] );
+
+ return TRUE;
+}
+
+
+BOOL
+columns(
+ DWORD dwCurrentPC,
+ PNTKD_EXTENSION_APIS lpExtensionApis,
+ LPSTR lpArgumentString
+)
+{
+ ULONG NoOfColumns;
+ int i;
+
+ SETCALLBACKS();
+
+ sscanf(lpArgumentString,"%ld",&NoOfColumns);
+
+ if (NoOfColumns > s_MaxNoOfColumns) {
+ // PRINTF( "No. Of Columns exceeds maximum(%ld) -- directive Ignored\n", s_MaxNoOfColumns );
+ } else {
+ s_NoOfColumns = NoOfColumns;
+ }
+
+ PRINTF("Not Yet Implemented\n");
+
+ return TRUE;
+}
+
+
+
+BOOL
+globals(
+ DWORD dwCurrentPC,
+ PNTKD_EXTENSION_APIS lpExtensionApis,
+ LPSTR lpArgumentString
+)
+{
+ DWORD dwAddress;
+ CHAR buf[ 100 ];
+ int i;
+ int c=0;
+
+ SETCALLBACKS();
+
+ strcpy( buf, "srv!" );
+
+ for( i=0; GlobalBool[i]; i++, c++ ) {
+ BOOL b;
+
+ strcpy( &buf[4], GlobalBool[i] );
+ dwAddress = (lpGetExpressionRoutine) ( buf );
+ if( dwAddress == 0 ) {
+ ERROR( "Unable to get address of %s\n", GlobalBool[i] );
+ continue;
+ }
+ if( !GetData( dwAddress,&b, sizeof(b)) )
+ return FALSE;
+
+ PRINTF( "%s%-30s %10s%s",
+ c&1 ? " " : "",
+ GlobalBool[i],
+ b ? " TRUE" : "FALSE",
+ c&1 ? "\n" : "" );
+ }
+
+ for( i=0; GlobalShort[i]; i++, c++ ) {
+ SHORT s;
+
+ strcpy( &buf[4], GlobalShort[i] );
+ dwAddress = (lpGetExpressionRoutine) ( buf );
+ if( dwAddress == 0 ) {
+ ERROR( "Unable to get address of %s\n", GlobalShort[i] );
+ continue;
+ }
+ if( !GetData( dwAddress,&s,sizeof(s)) )
+ return FALSE;
+
+ PRINTF( "%s%-30s %10d%s",
+ c&1 ? " " : "",
+ GlobalShort[i],
+ s,
+ c&1 ? "\n" : "" );
+ }
+
+ for( i=0; GlobalLong[i]; i++, c++ ) {
+ LONG l;
+
+ strcpy( &buf[4], GlobalLong[i] );
+ dwAddress = (lpGetExpressionRoutine) ( buf );
+ if( dwAddress == 0 ) {
+ ERROR( "Unable to get address of %s\n", GlobalLong[i] );
+ continue;
+ }
+ if( !GetData( dwAddress,&l, sizeof(l)) )
+ return FALSE;
+
+ PRINTF( "%s%-30s %10d%s",
+ c&1 ? " " : "",
+ GlobalLong[i],
+ l,
+ c&1 ? "\n" : "" );
+ }
+
+ PRINTF( "\n" );
+
+ return TRUE;
+}
+
+
+BOOL
+version
+(
+ DWORD dwCurrentPC,
+ PNTKD_EXTENSION_APIS lpExtensionApis,
+ LPSTR lpArgumentString
+)
+{
+#if VER_DEBUG
+ char *kind = "checked";
+#else
+ char *kind = "free";
+#endif
+
+ SETCALLBACKS();
+
+ PRINTF( "Redirector debugger Extension dll for %s build %u\n", kind, VER_PRODUCTBUILD );
+
+ return TRUE;
+}
+
+#define NAME_DELIMITER '@'
+#define NAME_DELIMITERS "@"
+#define INVALID_INDEX 0xffffffff
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+
+ULONG SearchStructs(LPSTR lpArgument)
+{
+ ULONG i = 0;
+ STRUCT_DESCRIPTOR *pStructs = Structs;
+ ULONG NameIndex = INVALID_INDEX;
+ ULONG ArgumentLength = strlen(lpArgument);
+ BOOLEAN fAmbigous = FALSE;
+
+
+ while ((pStructs->StructName != 0)) {
+ int Result = _strnicmp(lpArgument,
+ pStructs->StructName,
+ MIN(strlen(pStructs->StructName),ArgumentLength));
+
+ if (Result == 0) {
+ if (NameIndex != INVALID_INDEX) {
+ // We have encountered duplicate matches. Print out the
+ // matching strings and let the user disambiguate.
+ fAmbigous = TRUE;
+ break;
+ } else {
+ NameIndex = i;
+ }
+
+ }
+ pStructs++;i++;
+ }
+
+ if (fAmbigous) {
+ PRINTF("Ambigous Name Specification -- The following structs match\n");
+ PRINTF("%s\n",Structs[NameIndex].StructName);
+ PRINTF("%s\n",Structs[i].StructName);
+ while (pStructs->StructName != 0) {
+ if (_strnicmp(lpArgument,
+ pStructs->StructName,
+ MIN(strlen(pStructs->StructName),ArgumentLength)) == 0) {
+ PRINTF("%s\n",pStructs->StructName);
+ }
+ pStructs++;
+ }
+ PRINTF("Dumping Information for %s\n",Structs[NameIndex].StructName);
+ }
+
+ return(NameIndex);
+}
+
+VOID DisplayStructs()
+{
+ STRUCT_DESCRIPTOR *pStructs = Structs;
+
+ PRINTF("The following structs are handled .... \n");
+ while (pStructs->StructName != 0) {
+ PRINTF("\t%s\n",pStructs->StructName);
+ pStructs++;
+ }
+}
+
+BOOL
+dump(
+ DWORD dwCurrentPC,
+ PNTKD_EXTENSION_APIS lpExtensionApis,
+ LPSTR lpArgumentString
+)
+{
+ DWORD dwAddress;
+
+ SETCALLBACKS();
+
+ if( lpArgumentString && *lpArgumentString ) {
+ // Parse the argument string to determine the structure to be displayed.
+ // Scan for the NAME_DELIMITER ( '@' ).
+
+ LPSTR lpName = lpArgumentString;
+ LPSTR lpArgs = strpbrk(lpArgumentString, NAME_DELIMITERS);
+ ULONG Index;
+
+ if (lpArgs) {
+ //
+ // The specified command is of the form
+ // dump <name>@<address expr.>
+ //
+ // Locate the matching struct for the given name. In the case
+ // of ambiguity we seek user intervention for disambiguation.
+ //
+ // We do an inplace modification of the argument string to
+ // facilitate matching.
+ //
+ *lpArgs = '\0';
+
+ Index = SearchStructs(lpName);
+
+ //
+ // Let us restore the original value back.
+ //
+
+ *lpArgs = NAME_DELIMITER;
+
+ if (INVALID_INDEX != Index) {
+ BYTE DataBuffer[512];
+
+ dwAddress = (lpGetExpressionRoutine)( ++lpArgs );
+ if (GetData(dwAddress,DataBuffer,Structs[Index].StructSize)) {
+
+ PRINTF(
+ "++++++++++++++++ %s@%lx ++++++++++++++++\n",
+ Structs[Index].StructName,
+ dwAddress);
+ PrintStructFields(
+ dwAddress,
+ &DataBuffer,
+ Structs[Index].FieldDescriptors);
+ PRINTF(
+ "---------------- %s@%lx ----------------\n",
+ Structs[Index].StructName,
+ dwAddress);
+ } else {
+ PRINTF("Error reading Memory @ %lx\n",dwAddress);
+ }
+ } else {
+ // No matching struct was found. Display the list of
+ // structs currently handled.
+
+ DisplayStructs();
+ }
+ } else {
+ //
+ // The command is of the form
+ // dump <name>
+ //
+ // Currently we do not handle this. In future we will map it to
+ // the name of a global variable and display it if required.
+ //
+
+ DisplayStructs();
+ }
+ } else {
+ //
+ // display the list of structs currently handled.
+ //
+
+ DisplayStructs();
+ }
+
+ return TRUE;
+}
+
+#if 0
+BOOL
+logdump(
+ DWORD dwCurrentPC,
+ PNTKD_EXTENSION_APIS lpExtensionApis,
+ LPSTR lpArgumentString
+)
+{
+ DWORD dwAddress;
+ BYTE DataBuffer[512];
+
+ SETCALLBACKS();
+
+ if( lpArgumentString && *lpArgumentString ) {
+ RX_LOG RxLog;
+
+ dwAddress = (lpGetExpressionRoutine)(lpArgumentString);
+ if (GetData(dwAddress,&RxLog,sizeof(RX_LOG))) {
+ // Dump the log header followed by the log entries ...
+ ULONG dwCurEntry;
+
+ PRINTF("s_RxLog.State %lx\n",RxLog.State);
+ PRINTF("s_RxLog.pHeadEntry %lx\n",RxLog.pHeadEntry);
+ PRINTF("s_RxLog.pTailEntry %lx\n",RxLog.pTailEntry);
+ PRINTF("s_RxLog.LogBufferSize %lx\n",RxLog.LogBufferSize);
+ PRINTF("s_RxLog.pLogBuffer %lx\n",RxLog.pLogBuffer);
+ PRINTF("s_RxLog.pWrapAroundPoint %lx\n",RxLog.pWrapAroundPoint);
+ PRINTF("s_RxLog.NumberOfEntriesIgnored %lx\n",RxLog.NumberOfEntriesIgnored);
+ PRINTF("s_RxLog.NumberOfLogWriteAttempts %lx\n",RxLog.NumberOfLogWriteAttempts);
+
+ dwCurEntry = (DWORD)RxLog.pHeadEntry;
+ for (;;) {
+ PRX_LOG_ENTRY_HEADER pHeader;
+ ULONG LogRecordLength;
+ DWORD dwNextEntry;
+
+ if (!GetData(dwCurEntry,DataBuffer,sizeof(RX_LOG_ENTRY_HEADER))) {
+ PRINTF("Error reading Memory @ %lx\n",dwAddress);
+ break;
+ }
+
+ pHeader = (PRX_LOG_ENTRY_HEADER)DataBuffer;
+ LogRecordLength = pHeader->EntrySize - sizeof(RX_LOG_ENTRY_HEADER);
+ dwNextEntry = dwCurEntry + pHeader->EntrySize;
+
+ if ((pHeader->EntrySize > 0) &&
+ GetData((dwCurEntry + sizeof(RX_LOG_ENTRY_HEADER)),
+ DataBuffer,
+ LogRecordLength)) {
+ DataBuffer[LogRecordLength] = '\0';
+ PRINTF("%s",DataBuffer);
+ }
+
+
+ if (RxLog.pTailEntry > RxLog.pHeadEntry) {
+ if (dwNextEntry > (DWORD)RxLog.pTailEntry) {
+ break;
+ }
+ } else {
+ if (dwNextEntry > (DWORD)RxLog.pHeadEntry) {
+ if ((dwNextEntry >= (DWORD)RxLog.pWrapAroundPoint) ||
+ (dwNextEntry >= (DWORD)((PBYTE)RxLog.pLogBuffer + RxLog.LogBufferSize))) {
+ dwNextEntry = (DWORD)RxLog.pLogBuffer;
+ }
+ } else if (dwNextEntry > (DWORD)RxLog.pTailEntry) {
+ break;
+ }
+ }
+
+ dwCurEntry = dwNextEntry;
+ }
+ } else {
+ PRINTF("Error reading Memory @ %lx\n",dwAddress);
+ }
+ } else {
+ PRINTF("usage: logdump <log address>\n");
+ }
+
+ return TRUE;
+}
+#endif
+
diff --git a/private/ntos/nbt/nt/netbtkd/kdextlib.h b/private/ntos/nbt/nt/netbtkd/kdextlib.h
new file mode 100644
index 000000000..10bb0fbf9
--- /dev/null
+++ b/private/ntos/nbt/nt/netbtkd/kdextlib.h
@@ -0,0 +1,139 @@
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ rdr2kd.h
+
+Abstract:
+
+ Redirector Kernel Debugger extension
+
+Author:
+
+ Balan Sethu Raman (SethuR) 11-May-1994
+
+Revision History:
+
+ 11-Nov-1994 SethuR Created
+
+--*/
+
+#ifndef _KDEXTLIB_H_
+#define _KDEXTLIB_H_
+
+#include <windef.h>
+
+//
+// The help strings printed out
+//
+
+extern LPSTR Extensions[];
+
+//
+// The FIELD_DESCRIPTOR data structure is used to describe the field in a structure sufficiently
+// for displaying information during debugging. The three pieces of information that are required
+// are 1) the name of the field, 2) the offset in the corresponding structure and 3) a type descriptor.
+// The type descriptor covers most primitive types.
+//
+// The task of generating these descriptors by augmenting the front end, but that will have to
+// wait till we play around with these extensions and modify the data structures to meet most
+// of the requirements.
+//
+// There are some types that can benefit from some auxillary information in the descriptors. A
+// case in point is the "enum" defeinition. Merely printing out a numerical value for an enum
+// type will invariably force the person using these extensions to refer to the corresponding
+// include file. In order to avoid this we will accept an additional array for enum types that
+// contains a textual description of the numerical value.
+//
+// There are certain conventions that have been adopted to ease the definition of the macros
+// as well as facilitate the automation of the generation of these descriptors.
+// These are as follows ....
+//
+// 1) All ENUM_VALUE_DESCRIPTOR definitions are named EnumValueDescrsOf_ENUMTYPENAME, where
+// ENUMTYPENAME defines the corresponding enumerated type.
+//
+
+typedef struct _ENUM_VALUE_DESCRIPTOR {
+ ULONG EnumValue;
+ LPSTR EnumName;
+} ENUM_VALUE_DESCRIPTOR;
+
+typedef enum _FIELD_TYPE_CLASS {
+ FieldTypeByte,
+ FieldTypeChar,
+ FieldTypeBoolean,
+ FieldTypeBool,
+ FieldTypeULong,
+ FieldTypeLong,
+ FieldTypeUShort,
+ FieldTypeShort,
+ FieldTypePointer,
+ FieldTypeULongULong,
+ FieldTypeListEntry,
+ FieldTypeIpAddr,
+ FieldTypeMacAddr,
+ FieldTypeNBName,
+ FieldTypeUnicodeString,
+ FieldTypeAnsiString,
+ FieldTypeSymbol,
+ FieldTypeEnum,
+ FieldTypeByteBitMask,
+ FieldTypeWordBitMask,
+ FieldTypeDWordBitMask,
+ FieldTypeFloat,
+ FieldTypeDouble,
+ FieldTypeStruct,
+ FieldTypeLargeInteger,
+ FieldTypeFileTime
+} FIELD_TYPE_CLASS, *PFIELD_TYPE_CLASS;
+
+typedef struct _FIELD_DESCRIPTOR_ {
+ FIELD_TYPE_CLASS FieldType; // The type of variable to be printed
+ LPSTR Name; // The name of the field
+ USHORT Offset; // The offset of the field in the structure
+ union {
+ ENUM_VALUE_DESCRIPTOR *pEnumValueDescriptor; // Auxillary information for enumerated types.
+ } AuxillaryInfo;
+} FIELD_DESCRIPTOR;
+
+#define FIELD3(FieldType,StructureName, FieldName) \
+ {FieldType, #FieldName , FIELD_OFFSET(StructureName,FieldName) ,NULL}
+
+#define FIELD4(FieldType, StructureName, FieldName, AuxInfo) \
+ {FieldType, #FieldName , FIELD_OFFSET(StructureName,FieldName) ,AuxInfo}
+
+//
+// The structs that are displayed by the debugger extensions are further
+// described in another array. Each entry in the array contains the name of
+// the structure and the associated Field descriptor list.
+//
+
+typedef struct _STRUCT_DESCRITOR_ {
+ LPSTR StructName;
+ ULONG StructSize;
+ FIELD_DESCRIPTOR *FieldDescriptors;
+} STRUCT_DESCRIPTOR;
+
+#define STRUCT(StructTypeName,FieldDescriptors) \
+ { #StructTypeName,sizeof(StructTypeName),FieldDescriptors}
+
+//
+// The array of structs handled by the debugger extension.
+//
+
+extern STRUCT_DESCRIPTOR Structs[];
+
+//
+// Support for displaying global variables
+//
+
+extern LPSTR GlobalBool[];
+extern LPSTR GlobalShort[];
+extern LPSTR GlobalLong[];
+extern LPSTR GlobalPtrs[];
+
+#endif // _KDEXTLIB_H_
+
diff --git a/private/ntos/nbt/nt/netbtkd/makefile b/private/ntos/nbt/nt/netbtkd/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/nbt/nt/netbtkd/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/nbt/nt/netbtkd/netbtkd.c b/private/ntos/nbt/nt/netbtkd/netbtkd.c
new file mode 100644
index 000000000..6e1c60b41
--- /dev/null
+++ b/private/ntos/nbt/nt/netbtkd/netbtkd.c
@@ -0,0 +1,369 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ netbtkd.c
+
+Abstract:
+
+ Netbt Kernel Debugger extension
+
+Author:
+
+ Shirish Koti
+
+Revision History:
+
+ 6-Jun-1991 Koti Created
+
+--*/
+
+#include "types.h"
+
+#include <kdextlib.h>
+
+/*
+ * RDR2 global variables.
+ *
+ */
+
+LPSTR GlobalBool[] = {0};
+LPSTR GlobalShort[] = {0};
+LPSTR GlobalLong[] = {0};
+LPSTR GlobalPtrs[] = {0};
+
+LPSTR Extensions[] = {
+ "Netbt debugger extensions",
+ 0
+};
+
+/*
+ * DeviceContext debugging.
+ *
+ */
+
+FIELD_DESCRIPTOR DeviceContext[] =
+ {
+ FIELD3(FieldTypeStruct,tDEVICECONTEXT,DeviceObject),
+ FIELD3(FieldTypeListEntry,tDEVICECONTEXT,Linkage),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,SpinLock),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,Verify),
+ FIELD3(FieldTypeListEntry,tDEVICECONTEXT,UpConnectionInUse),
+ FIELD3(FieldTypeListEntry,tDEVICECONTEXT,LowerConnection),
+ FIELD3(FieldTypeListEntry,tDEVICECONTEXT,LowerConnFreeHead),
+ FIELD3(FieldTypeUnicodeString,tDEVICECONTEXT,BindName),
+ FIELD3(FieldTypeUnicodeString,tDEVICECONTEXT,ExportName),
+ FIELD3(FieldTypeIpAddr,tDEVICECONTEXT,IpAddress),
+ FIELD3(FieldTypeIpAddr,tDEVICECONTEXT,SubnetMask),
+ FIELD3(FieldTypeIpAddr,tDEVICECONTEXT,BroadcastAddress),
+ FIELD3(FieldTypeIpAddr,tDEVICECONTEXT,NetMask),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,hNameServer),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,pNameServerDeviceObject),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,pNameServerFileObject),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,hDgram),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,pDgramDeviceObject),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,pDgramFileObject),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,hSession),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,pSessionDeviceObject),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,pSessionFileObject),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,hControl),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,pControlDeviceObject),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,pControlFileObject),
+ FIELD3(FieldTypeIpAddr,tDEVICECONTEXT,lNameServerAddress),
+ FIELD3(FieldTypeIpAddr,tDEVICECONTEXT,lBackupServer),
+ FIELD3(FieldTypePointer,tDEVICECONTEXT,pPermClient),
+ FIELD3(FieldTypeULongULong,tDEVICECONTEXT,AdapterNumber),
+ FIELD3(FieldTypeMacAddr,tDEVICECONTEXT,MacAddress),
+ FIELD3(FieldTypeChar,tDEVICECONTEXT,LockNumber),
+ FIELD3(FieldTypeBoolean,tDEVICECONTEXT,RefreshToBackup),
+ FIELD3(FieldTypeBoolean,tDEVICECONTEXT,PointToPoint),
+ FIELD3(FieldTypeBoolean,tDEVICECONTEXT,WinsIsDown),
+ 0
+ };
+
+FIELD_DESCRIPTOR NameAddr[] =
+ {
+ FIELD3(FieldTypeListEntry,tNAMEADDR,Linkage),
+ FIELD3(FieldTypePointer,tNAMEADDR,pAddressEle),
+ FIELD3(FieldTypeIpAddr,tNAMEADDR,IpAddress),
+ FIELD3(FieldTypePointer,tNAMEADDR,pIpAddrsList),
+ FIELD3(FieldTypePointer,tNAMEADDR,pTracker),
+ FIELD3(FieldTypePointer,tNAMEADDR,pTimer),
+ FIELD3(FieldTypePointer,tNAMEADDR,Ttl),
+ FIELD3(FieldTypeULong,tNAMEADDR,RefCount),
+ FIELD3(FieldTypePointer,tNAMEADDR,NameTypeState),
+ FIELD3(FieldTypePointer,tNAMEADDR,Verify),
+ FIELD3(FieldTypeULongULong,tNAMEADDR,AdapterMask),
+ FIELD3(FieldTypeULongULong,tNAMEADDR,RefreshMask),
+ FIELD3(FieldTypeUShort,tNAMEADDR,TimeOutCount),
+ FIELD3(FieldTypeBoolean,tNAMEADDR,fProxyReq),
+#ifdef PROXY_NODE
+ FIELD3(FieldTypeBoolean,tNAMEADDR,fPnode),
+#endif
+ FIELD3(FieldTypeNBName,tNAMEADDR,Name),
+ 0
+ };
+
+FIELD_DESCRIPTOR AddressEle[] =
+ {
+ FIELD3(FieldTypeListEntry,tADDRESSELE,Linkage),
+ FIELD3(FieldTypePointer,tADDRESSELE,Verify),
+ FIELD3(FieldTypePointer,tADDRESSELE,SpinLock),
+ FIELD3(FieldTypeListEntry,tADDRESSELE,ClientHead),
+ FIELD3(FieldTypePointer,tADDRESSELE,pNameAddr),
+ FIELD3(FieldTypeULong,tADDRESSELE,RefCount),
+ FIELD3(FieldTypePointer,tADDRESSELE,pDeviceContext),
+ FIELD3(FieldTypePointer,tADDRESSELE,SecurityDescriptor),
+ FIELD3(FieldTypeUShort,tADDRESSELE,NameType),
+ FIELD3(FieldTypeChar,tADDRESSELE,LockNumber),
+ FIELD3(FieldTypeBoolean,tADDRESSELE,MultiClients),
+ 0
+ };
+
+FIELD_DESCRIPTOR ClientEle[] =
+ {
+ FIELD3(FieldTypeListEntry,tCLIENTELE,Linkage),
+ FIELD3(FieldTypePointer,tCLIENTELE,Verify),
+ FIELD3(FieldTypePointer,tCLIENTELE,pIrp),
+ FIELD3(FieldTypePointer,tCLIENTELE,SpinLock),
+ FIELD3(FieldTypePointer,tCLIENTELE,pAddress),
+ FIELD3(FieldTypeListEntry,tCLIENTELE,ConnectHead),
+ FIELD3(FieldTypeListEntry,tCLIENTELE,ConnectActive),
+ FIELD3(FieldTypeListEntry,tCLIENTELE,RcvDgramHead),
+ FIELD3(FieldTypeListEntry,tCLIENTELE,ListenHead),
+ FIELD3(FieldTypeListEntry,tCLIENTELE,SndDgrams),
+ FIELD3(FieldTypePointer,tCLIENTELE,evConnect),
+ FIELD3(FieldTypePointer,tCLIENTELE,ConEvContext),
+ FIELD3(FieldTypePointer,tCLIENTELE,evReceive),
+ FIELD3(FieldTypePointer,tCLIENTELE,RcvEvContext),
+ FIELD3(FieldTypePointer,tCLIENTELE,evDisconnect),
+ FIELD3(FieldTypePointer,tCLIENTELE,DiscEvContext),
+ FIELD3(FieldTypePointer,tCLIENTELE,evError),
+ FIELD3(FieldTypePointer,tCLIENTELE,ErrorEvContext),
+ FIELD3(FieldTypePointer,tCLIENTELE,evRcvDgram),
+ FIELD3(FieldTypePointer,tCLIENTELE,RcvDgramEvContext),
+ FIELD3(FieldTypePointer,tCLIENTELE,evRcvExpedited),
+ FIELD3(FieldTypePointer,tCLIENTELE,RcvExpedEvContext),
+ FIELD3(FieldTypePointer,tCLIENTELE,evSendPossible),
+ FIELD3(FieldTypePointer,tCLIENTELE,SendPossEvContext),
+ FIELD3(FieldTypePointer,tCLIENTELE,pDeviceContext),
+ FIELD3(FieldTypeULong,tCLIENTELE,RefCount),
+ FIELD3(FieldTypeChar,tCLIENTELE,LockNumber),
+ FIELD3(FieldTypeBoolean,tCLIENTELE,WaitingForRegistration),
+ 0
+ };
+
+
+FIELD_DESCRIPTOR ConnectEle[] =
+ {
+ FIELD3(FieldTypeListEntry,tCONNECTELE,Linkage),
+ FIELD3(FieldTypePointer,tCONNECTELE,Verify),
+ FIELD3(FieldTypePointer,tCONNECTELE,SpinLock),
+ FIELD3(FieldTypePointer,tCONNECTELE,pLowerConnId),
+ FIELD3(FieldTypePointer,tCONNECTELE,pClientEle),
+ FIELD3(FieldTypePointer,tCONNECTELE,ConnectContext),
+ FIELD3(FieldTypeNBName,tCONNECTELE,RemoteName),
+ FIELD3(FieldTypePointer,tCONNECTELE,pNewMdl),
+ FIELD3(FieldTypeULong,tCONNECTELE,CurrentRcvLen),
+ FIELD3(FieldTypeULong,tCONNECTELE,FreeBytesInMdl),
+ FIELD3(FieldTypeULong,tCONNECTELE,TotalPcktLen),
+ FIELD3(FieldTypeULong,tCONNECTELE,BytesInXport),
+ FIELD3(FieldTypeULong,tCONNECTELE,BytesRcvd),
+ FIELD3(FieldTypeULong,tCONNECTELE,ReceiveIndicated),
+ FIELD3(FieldTypePointer,tCONNECTELE,pNextMdl),
+ FIELD3(FieldTypeULong,tCONNECTELE,OffsetFromStart),
+ FIELD3(FieldTypePointer,tCONNECTELE,pIrp),
+ FIELD3(FieldTypePointer,tCONNECTELE,pIrpClose),
+ FIELD3(FieldTypePointer,tCONNECTELE,pIrpDisc),
+ FIELD3(FieldTypePointer,tCONNECTELE,pIrpRcv),
+ FIELD3(FieldTypeULong,tCONNECTELE,RefCount),
+ FIELD3(FieldTypeULong,tCONNECTELE,state),
+ FIELD3(FieldTypeBoolean,tCONNECTELE,Orig),
+ FIELD3(FieldTypeChar,tCONNECTELE,LockNumber),
+ FIELD3(FieldTypeChar,tCONNECTELE,SessionSetupCount),
+ FIELD3(FieldTypeChar,tCONNECTELE,DiscFlag),
+ FIELD3(FieldTypeBoolean,tCONNECTELE,JunkMsgFlag),
+ 0
+ };
+
+FIELD_DESCRIPTOR LowerConn[] =
+ {
+ FIELD3(FieldTypeListEntry,tLOWERCONNECTION,Linkage),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,Verify),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,SpinLock),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,pUpperConnection),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,FileHandle),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,pFileObject),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,AddrFileHandle),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,pAddrFileObject),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,pDeviceContext),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,pIndicateMdl),
+ FIELD3(FieldTypeULongULong,tLOWERCONNECTION,BytesRcvd),
+ FIELD3(FieldTypeULongULong,tLOWERCONNECTION,BytesSent),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,pMdl),
+ FIELD3(FieldTypeUShort,tLOWERCONNECTION,BytesInIndicate),
+ FIELD3(FieldTypeUShort,tLOWERCONNECTION,StateRcv),
+ FIELD3(FieldTypeIpAddr,tLOWERCONNECTION,SrcIpAddr),
+ FIELD3(FieldTypeULong,tLOWERCONNECTION,State),
+ FIELD3(FieldTypeULong,tLOWERCONNECTION,RefCount),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,pIrp),
+ FIELD3(FieldTypePointer,tLOWERCONNECTION,CurrentStateProc),
+ FIELD3(FieldTypeBoolean,tLOWERCONNECTION,bReceivingToIndicateBuffer),
+ FIELD3(FieldTypeChar,tLOWERCONNECTION,LockNumber),
+ FIELD3(FieldTypeBoolean,tLOWERCONNECTION,bOriginator),
+ FIELD3(FieldTypeBoolean,tLOWERCONNECTION,InRcvHandler),
+ FIELD3(FieldTypeBoolean,tLOWERCONNECTION,DestroyConnection),
+ 0
+ };
+
+
+FIELD_DESCRIPTOR Tracker[] =
+ {
+ FIELD3(FieldTypeListEntry,tDGRAM_SEND_TRACKING,Linkage),
+ FIELD3(FieldTypeListEntry,tDGRAM_SEND_TRACKING,TrackerList),
+ FIELD3(FieldTypePointer,tDGRAM_SEND_TRACKING,Verify),
+ FIELD3(FieldTypePointer,tDGRAM_SEND_TRACKING,pClientIrp),
+ FIELD3(FieldTypePointer,tDGRAM_SEND_TRACKING,pConnEle),
+ FIELD3(FieldTypeStruct,tDGRAM_SEND_TRACKING,SendBuffer),
+ FIELD3(FieldTypePointer,tDGRAM_SEND_TRACKING,pSendInfo),
+ FIELD3(FieldTypePointer,tDGRAM_SEND_TRACKING,pDeviceContext),
+ FIELD3(FieldTypePointer,tDGRAM_SEND_TRACKING,pTimer),
+ FIELD3(FieldTypePointer,tDGRAM_SEND_TRACKING,RefCount),
+ FIELD3(FieldTypePointer,tDGRAM_SEND_TRACKING,pNameAddr),
+ FIELD3(FieldTypePointer,tDGRAM_SEND_TRACKING,pTimeout),
+ FIELD3(FieldTypePointer,tDGRAM_SEND_TRACKING,AllocatedLength),
+ FIELD3(FieldTypePointer,tDGRAM_SEND_TRACKING,CompletionRoutine),
+ FIELD3(FieldTypeUShort,tDGRAM_SEND_TRACKING,Flags),
+ FIELD3(FieldTypeListEntry,tDGRAM_SEND_TRACKING,DebugLinkage),
+ 0
+ };
+
+FIELD_DESCRIPTOR Nbt_Config[] =
+ {
+ FIELD3(FieldTypePointer,tNBTCONFIG,SpinLock),
+ FIELD3(FieldTypeULong,tNBTCONFIG,NumConnections),
+ FIELD3(FieldTypeULong,tNBTCONFIG,NumAddresses),
+ FIELD3(FieldTypeListEntry,tNBTCONFIG,DeviceContexts),
+ FIELD3(FieldTypeListEntry,tNBTCONFIG,DgramTrackerFreeQ),
+ FIELD3(FieldTypeListEntry,tNBTCONFIG,NodeStatusHead),
+ FIELD3(FieldTypeListEntry,tNBTCONFIG,AddressHead),
+ FIELD3(FieldTypeListEntry,tNBTCONFIG,PendingNameQueries),
+ FIELD3(FieldTypePointer,tNBTCONFIG,pControlObj),
+ FIELD3(FieldTypePointer,tNBTCONFIG,DriverObject),
+ FIELD3(FieldTypeListEntry,tNBTCONFIG,IrpFreeList),
+ FIELD3(FieldTypePointer,tNBTCONFIG,SessionMdlFreeSingleList),
+ FIELD3(FieldTypePointer,tNBTCONFIG,DgramMdlFreeSingleList),
+ FIELD3(FieldTypePointer,tNBTCONFIG,pTcpBindName),
+ FIELD3(FieldTypePointer,tNBTCONFIG,pLocalHashTbl),
+ FIELD3(FieldTypePointer,tNBTCONFIG,pRemoteHashTbl),
+ FIELD3(FieldTypeStruct,tNBTCONFIG,OutOfRsrc),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,uNumDevices),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,uNumLocalNames),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,uNumRemoteNames),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,uNumBucketsRemote),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,uNumBucketsLocal),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,TimerQSize),
+ FIELD3(FieldTypeULong,tNBTCONFIG,uBcastTimeout),
+ FIELD3(FieldTypeULong,tNBTCONFIG,uRetryTimeout),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,uNumRetries),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,uNumBcasts),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,ScopeLength),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,SizeTransportAddress),
+ FIELD3(FieldTypePointer,tNBTCONFIG,pScope),
+ FIELD3(FieldTypePointer,tNBTCONFIG,pBcastNetbiosName),
+ FIELD3(FieldTypeULong,tNBTCONFIG,MinimumTtl),
+ FIELD3(FieldTypeULong,tNBTCONFIG,RefreshDivisor),
+ FIELD3(FieldTypeULong,tNBTCONFIG,RemoteHashTimeout),
+ FIELD3(FieldTypeULong,tNBTCONFIG,WinsDownTimeout),
+ FIELD3(FieldTypePointer,tNBTCONFIG,pRefreshTimer),
+ FIELD3(FieldTypePointer,tNBTCONFIG,pSessionKeepAliveTimer),
+ FIELD3(FieldTypePointer,tNBTCONFIG,pRemoteHashTimer),
+ FIELD3(FieldTypeULong,tNBTCONFIG,InitialRefreshTimeout),
+ FIELD3(FieldTypeULong,tNBTCONFIG,KeepAliveTimeout),
+ FIELD3(FieldTypeULong,tNBTCONFIG,RegistryBcastAddr),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,DhcpNumConnections),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,CurrentHashBucket),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,PduNodeType),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,TransactionId),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,NameServerPort),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,sTimeoutCount),
+ FIELD3(FieldTypeStruct,tNBTCONFIG,JointLock),
+ FIELD3(FieldTypeChar,tNBTCONFIG,LockNumber),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,RemoteTimeoutCount),
+ FIELD3(FieldTypeBoolean,tNBTCONFIG,UseRegistryBcastAddr),
+ FIELD3(FieldTypeULong,tNBTCONFIG,MaxDgramBuffering),
+ FIELD3(FieldTypeULong,tNBTCONFIG,LmHostsTimeout),
+ FIELD3(FieldTypePointer,tNBTCONFIG,pLmHosts),
+ FIELD3(FieldTypeULong,tNBTCONFIG,PathLength),
+ FIELD3(FieldTypeChar,tNBTCONFIG,AdapterCount),
+ FIELD3(FieldTypeBoolean,tNBTCONFIG,MultiHomed),
+ FIELD3(FieldTypeBoolean,tNBTCONFIG,SingleResponse),
+ FIELD3(FieldTypeBoolean,tNBTCONFIG,SelectAdapter),
+ FIELD3(FieldTypeBoolean,tNBTCONFIG,ResolveWithDns),
+ FIELD3(FieldTypeBoolean,tNBTCONFIG,EnableLmHosts),
+ FIELD3(FieldTypeBoolean,tNBTCONFIG,EnableProxyRegCheck),
+ FIELD3(FieldTypeBoolean,tNBTCONFIG,DoingRefreshNow),
+ FIELD3(FieldTypeChar,tNBTCONFIG,CurrProc),
+ FIELD3(FieldTypeUShort,tNBTCONFIG,OpRefresh),
+ 0
+ };
+
+
+FIELD_DESCRIPTOR NbtWorkContext[] =
+ {
+ FIELD3(FieldTypeStruct,NBT_WORK_ITEM_CONTEXT,Item),
+ FIELD3(FieldTypePointer,NBT_WORK_ITEM_CONTEXT,pTracker),
+ FIELD3(FieldTypePointer,NBT_WORK_ITEM_CONTEXT,pClientContext),
+ FIELD3(FieldTypePointer,NBT_WORK_ITEM_CONTEXT,ClientCompletion),
+ FIELD3(FieldTypeBoolean,NBT_WORK_ITEM_CONTEXT,TimedOut),
+ 0
+ };
+
+
+FIELD_DESCRIPTOR Timer_Entry[] =
+ {
+ FIELD3(FieldTypeStruct,tTIMERQENTRY,VxdTimer),
+ FIELD3(FieldTypeListEntry,tTIMERQENTRY,Linkage),
+ FIELD3(FieldTypePointer,tTIMERQENTRY,Context),
+ FIELD3(FieldTypePointer,tTIMERQENTRY,Context2),
+ FIELD3(FieldTypePointer,tTIMERQENTRY,CompletionRoutine),
+ FIELD3(FieldTypePointer,tTIMERQENTRY,ClientContext),
+ FIELD3(FieldTypePointer,tTIMERQENTRY,ClientCompletion),
+ FIELD3(FieldTypePointer,tTIMERQENTRY,pCacheEntry),
+ FIELD3(FieldTypeULong,tTIMERQENTRY,DeltaTime),
+ FIELD3(FieldTypeUShort,tTIMERQENTRY,Flags),
+ FIELD3(FieldTypeUShort,tTIMERQENTRY,Retries),
+ FIELD3(FieldTypeChar,tTIMERQENTRY,RefCount),
+ 0
+ };
+
+FIELD_DESCRIPTOR Dns_Queries[] =
+ {
+ FIELD3(FieldTypePointer,tDNS_QUERIES,QueryIrp),
+ FIELD3(FieldTypeListEntry,tDNS_QUERIES,ToResolve),
+ FIELD3(FieldTypePointer,tDNS_QUERIES,Context),
+ FIELD3(FieldTypeBoolean,tDNS_QUERIES,ResolvingNow),
+ 0
+ };
+
+//
+// List of structs currently handled by the debugger extensions
+//
+
+STRUCT_DESCRIPTOR Structs[] =
+ {
+ STRUCT(tDEVICECONTEXT,DeviceContext),
+ STRUCT(tNAMEADDR,NameAddr),
+ STRUCT(tADDRESSELE,AddressEle),
+ STRUCT(tCLIENTELE,ClientEle),
+ STRUCT(tCONNECTELE,ConnectEle),
+ STRUCT(tLOWERCONNECTION,LowerConn),
+ STRUCT(tDGRAM_SEND_TRACKING,Tracker),
+ STRUCT(tNBTCONFIG,Nbt_Config),
+ STRUCT(NBT_WORK_ITEM_CONTEXT,NbtWorkContext),
+ STRUCT(tTIMERQENTRY,Timer_Entry),
+ STRUCT(tDNS_QUERIES,Dns_Queries),
+ 0
+ };
diff --git a/private/ntos/nbt/nt/netbtkd/netbtkd.def b/private/ntos/nbt/nt/netbtkd/netbtkd.def
new file mode 100644
index 000000000..3e91e095e
--- /dev/null
+++ b/private/ntos/nbt/nt/netbtkd/netbtkd.def
@@ -0,0 +1,8 @@
+LIBRARY NETBTKD
+DESCRIPTION 'Netbt KD extensions'
+
+EXPORTS
+ help
+ dump
+ columns
+
diff --git a/private/ntos/nbt/nt/netbtkd/sources b/private/ntos/nbt/nt/netbtkd/sources
new file mode 100644
index 000000000..f8bca6009
--- /dev/null
+++ b/private/ntos/nbt/nt/netbtkd/sources
@@ -0,0 +1,53 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=netbt
+
+TARGETNAME=netbtkd
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\libc.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib\
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib
+
+C_DEFINES=-DPROXY_NODE
+INCLUDES=..;..\inc;..\..\inc;..\..\..\inc;..\..\..\..\inc
+
+!IFNDEF DISABLE_NET_UNICODE
+UNICODE=1
+NET_C_DEFINES=-DUNICODE
+!ENDIF
+
+DLLBASE=0x1010000
+
+C_DEFINES=$(C_DEFINES) -DRDBSSDBG
+
+SOURCES=kdextlib.c \
+ netbtkd.c
+
+UMTYPE=console
+OPTIONAL_NTTEST=
+
+
diff --git a/private/ntos/nbt/nt/ntisol.c b/private/ntos/nbt/nt/ntisol.c
new file mode 100644
index 000000000..2f3e532cc
--- /dev/null
+++ b/private/ntos/nbt/nt/ntisol.c
@@ -0,0 +1,4873 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Ntisol.h
+
+Abstract:
+
+
+ This file contains the interface between the TDI interface on the top
+ of NBT and the OS independent code. It takes the parameters out of the
+ irps and puts in into procedure calls for the OS independent code (which
+ is mostly in name.c).
+
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+Notes:
+
+ The Nbt routines have been modified to include an additional parameter, i.e,
+ the transport type. This transport type is used primarily to distinguish the
+ NETBIOS over TCP/IP implementation from the Messaging Over TCP/IP implementation.
+
+ The primary difference between the two being that the later uses the NETBT framing
+ without the associated NETBIOS name registartion/resolution. It primarily uses
+ DNS for name resolution. All the names that are registered for the new transport
+ are local names and are not defended on the network.
+
+ The primary usage is in conjuntion with an extended NETBIOS address type defined
+ in tdi.h. The NETBIOS name resolution/registration traffic occurs in two phases.
+ The first phase contains all the broadcast traffic that ensues during NETBIOS
+ name registration. Subsequently the NETBT implementation queries the remote
+ adapter status to choose the appropriate called name. This approach results in
+ additional traffic for querying the remote adapter status. The new address type
+ defined in tdi.h enables the client of netbt to supply the name to be used in
+ NETBT session setup. This avoids the network traffic for querying the adapter
+ status.
+
+ The original design which has not been fully implemented involved exposing two
+ device objects from the NetBt driver -- the NetBt device object which would be
+ the full implementation of NETBIOS over TCP/IP and the MoTcp device object which
+ would be the implementation of Messaging over TCP/IP. The MoTcp device object
+ would use the same port address as NetBt and use the same session setup protocol
+ to talk to remote machines running old NetBt drivers and machines running new
+ NetBt drivers.
+
+ The transport type variations combined with the address type changes present us
+ with four different cases which need to be handled -- the NetBt transport being
+ presented with a TDI_ADDRESS_NETBIOS_EX structure, the NetBt transport being
+ prsented with a TDI_ADDRESS_NETBIOS structure and the same two cases for the
+ MoTcp transport.
+
+--*/
+
+#include "types.h"
+#include "nbtprocs.h"
+#include "ntprocs.h"
+#include <nbtioctl.h>
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+
+NTSTATUS
+SendCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+
+NTSTATUS
+NTSendCleanupConnection(
+ IN tCONNECTELE *pConnEle,
+ IN PVOID pCompletionRoutine,
+ IN PVOID Context,
+ IN PIRP pIrp);
+
+VOID
+DpcSendSession(
+ IN PKDPC pDpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+NBT_WORK_ITEM_CONTEXT *
+DnsIrpCancelPaged(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+
+ NBT_WORK_ITEM_CONTEXT *
+FindCheckAddrIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+NTCancelCancelRoutine(
+ IN PIRP pIrp
+ );
+
+#ifdef RASAUTODIAL
+extern ACD_DRIVER AcdDriverG;
+
+BOOLEAN
+NbtCancelPostConnect(
+ IN PIRP pIrp
+ );
+#endif // RASAUTODIAL
+
+NTSTATUS
+NbtQueryGetAddressInfo(
+ IN PIO_STACK_LOCATION pIrpSp,
+ OUT PVOID *ppBuffer,
+ OUT ULONG *pSize
+);
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, NTOpenControl)
+#pragma CTEMakePageable(PAGE, NTOpenAddr)
+#pragma CTEMakePageable(PAGE, NTCloseAddress)
+#pragma CTEMakePageable(PAGE, NTOpenConnection)
+#pragma CTEMakePageable(PAGE, NTAssocAddress)
+#pragma CTEMakePageable(PAGE, NTCloseConnection)
+#pragma CTEMakePageable(PAGE, NTSetSharedAccess)
+#pragma CTEMakePageable(PAGE, NTCheckSharedAccess)
+#pragma CTEMakePageable(PAGE, NTCleanUpConnection)
+#pragma CTEMakePageable(PAGE, NTCleanUpAddress)
+#pragma CTEMakePageable(PAGE, NTDisAssociateAddress)
+#pragma CTEMakePageable(PAGE, NTListen)
+//
+// Should not be pageable since AFD can call us at raised Irql in case of AcceptEx.
+//
+// #pragma CTEMakePageable(PAGE, NTQueryInformation)
+#pragma CTEMakePageable(PAGE, DispatchIoctls)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTOpenControl(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+/*++
+Routine Description:
+
+ This Routine handles opening the control object, which represents the
+ driver itself. For example QueryInformation uses the control object
+ as the destination of the Query message.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS status;
+
+ CTEPagedCode();
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ pIrpSp->FileObject->FsContext2 = (PVOID)(NBT_CONTROL_TYPE);
+
+ // return a ptr the control endpoint
+ pIrpSp->FileObject->FsContext = (PVOID)pNbtGlobConfig->pControlObj;
+
+ //
+ // the following call opens a control object with the transport below since
+ // several of the query information calls are passed directly on to the
+ // transport below.
+ //
+ if (!pDeviceContext->pControlFileObject)
+ {
+ status = NbtTdiOpenControl(pDeviceContext);
+ }
+ else
+ status = STATUS_SUCCESS;
+
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTOpenAddr(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+/*++
+Routine Description:
+
+ This Routine handles converting an Open Address Request from an IRP to
+ a procedure call so that NbtOpenAddress can be called in an OS independent
+ manner.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ TDI_REQUEST Request;
+ PVOID pSecurityDesc;
+ TRANSPORT_ADDRESS UNALIGNED *pTransportAddr; // structure containing counted array of TA_ADDRESS
+ TA_ADDRESS UNALIGNED *pAddress;
+ PTDI_ADDRESS_NETBIOS pNetbiosAddress;
+ PFILE_FULL_EA_INFORMATION ea;
+ int j;
+ NTSTATUS status=STATUS_INVALID_ADDRESS_COMPONENT;
+
+ CTEPagedCode();
+
+ // make up the Request data structure from the IRP info
+ Request.Handle.AddressHandle = NULL;
+
+ ea = (PFILE_FULL_EA_INFORMATION)pIrp->AssociatedIrp.SystemBuffer;
+ pTransportAddr = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+
+ pAddress = NULL;
+
+ // loop through the addresses passed in until ONE is successfully used
+ // *TODO* is it really necessary to have this loop or can we just assume
+ // the name is at the start of the address buffer...
+ // *TODO does this need to handle multiple names??
+ for (j=0;j < pTransportAddr->TAAddressCount ;j++ )
+ {
+ // this includes the address type as well as the actual address
+ pAddress = &pTransportAddr->Address[j];
+ switch (pAddress->AddressType) {
+ case TDI_ADDRESS_TYPE_NETBIOS:
+ {
+ if (pAddress->AddressLength == 0)
+ {
+ // zero length addresses mean the broadcast address
+ pAddress = NULL;
+ }
+
+ // call the non-NT specific function to open an address
+ status = NbtOpenAddress(&Request,
+ pAddress,
+ pDeviceContext->IpAddress,
+ &pSecurityDesc,
+ pDeviceContext,
+ (PVOID)pIrp);
+ }
+ break;
+ case TDI_ADDRESS_TYPE_NETBIOS_EX:
+ {
+
+ TDI_ADDRESS_NETBIOS NetbiosAddress;
+ PTDI_ADDRESS_NETBIOS_EX pNetbiosExAddress;
+
+ pNetbiosExAddress = (PTDI_ADDRESS_NETBIOS_EX)pAddress->Address;
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT..Opening NETBIOS_EX Address with Endpoint Name %16s\n",pNetbiosExAddress->EndpointName));
+
+ if (pAddress->AddressLength == 0) {
+ status = STATUS_INVALID_ADDRESS_COMPONENT;
+ } else {
+ // call the non-NT specific function to open an address
+ status = NbtOpenAddress(&Request,
+ pAddress,
+ pDeviceContext->IpAddress,
+ &pSecurityDesc,
+ pDeviceContext,
+ (PVOID)pIrp);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return(status);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTCloseAddress(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles converting a Close Address Request from an IRP to
+ a procedure call so that NbtCloseAddress can be called in an OS independent
+ manner.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+
+ TDI_REQUEST Request;
+ TDI_REQUEST_STATUS RequestStatus;
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS status;
+
+ CTEPagedCode();
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ Request.Handle.ConnectionContext = pIrpSp->FileObject->FsContext;
+
+
+ status = NbtCloseAddress(
+ &Request,
+ &RequestStatus,
+ pDeviceContext,
+ (PVOID)pIrp);
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTOpenConnection(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles converting an Open Connection Request from an IRP to
+ a procedure call so that NbtOpenConnection can be called in an OS independent
+ manner. The connection must be associated with an address before it
+ can be used, except for in inbound call where the client returns the
+ connection ID in the accept.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+
+ TDI_REQUEST Request;
+ PFILE_FULL_EA_INFORMATION ea;
+ PIO_STACK_LOCATION pIrpSp;
+ CONNECTION_CONTEXT ConnectionContext;
+ NTSTATUS status;
+ PFILE_OBJECT pFileObject;
+
+ CTEPagedCode();
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+
+ // make up the Request data structure from the IRP info
+ Request.Handle.ConnectionContext = NULL;
+
+ // get the connection context out of the System buffer
+ ea = (PFILE_FULL_EA_INFORMATION)pIrp->AssociatedIrp.SystemBuffer;
+
+ // the connection context value is stored in the string just after the
+ // name "connectionContext", and it is most likely unaligned, so just
+ // copy it out.( 4 bytes of copying ).
+ CTEMemCopy(&ConnectionContext,
+ (CONNECTION_CONTEXT)&ea->EaName[ea->EaNameLength+1],
+ sizeof(CONNECTION_CONTEXT));
+
+ // call the non-NT specific function to open an address
+ status = NbtOpenConnection(
+ &Request,
+ ConnectionContext,
+ pDeviceContext
+ );
+
+ pFileObject = pIrpSp->FileObject;
+
+ if (!NT_SUCCESS(status))
+ {
+ pFileObject->FsContext = NULL;
+ }
+ else
+ if (Request.Handle.ConnectionContext)
+ {
+
+ // fill the IRP with successful completion information so we can
+ // find the connection object given the fileObject later.
+ pFileObject->FsContext = Request.Handle.ConnectionContext;
+ pFileObject->FsContext2 = (PVOID)(NBT_CONNECTION_TYPE);
+ status = STATUS_SUCCESS;
+ }
+
+ return(status);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTAssocAddress(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles converting an Associate Address Request from an IRP to
+ a procedure call so that NbtAssociateAddress can be called in an OS independent
+ manner.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+
+ TDI_REQUEST Request;
+ PIO_STACK_LOCATION pIrpSp;
+ PVOID hAddress;
+ PFILE_OBJECT fileObject;
+ PTDI_REQUEST_KERNEL_ASSOCIATE parameters; // holds address handle
+ NTSTATUS status;
+
+ CTEPagedCode();
+
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ Request.Handle.ConnectionContext = pIrpSp->FileObject->FsContext;
+
+ // the address handle is buried in the Irp...
+ parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&pIrpSp->Parameters;
+
+ // now get a pointer to the file object, which points to the address
+ // element by calling a kernel routine to convert this filehandle into
+ // a file pointer.
+
+ status = ObReferenceObjectByHandle(
+ parameters->AddressHandle,
+ 0L,
+ 0,
+ KernelMode,
+ (PVOID *)&fileObject,
+ NULL);
+
+ if (NT_SUCCESS(status))
+ {
+ hAddress = (PVOID)fileObject->FsContext;
+ // call the non-NT specific function to associate the address with
+ // the connection
+ status = NbtAssociateAddress(
+ &Request,
+ (tCLIENTELE *)hAddress,
+ (PVOID)pIrp);
+
+ // we are done with the file object, so release the reference
+ ObDereferenceObject((PVOID)fileObject);
+
+ return(status);
+ }
+ else
+ return(STATUS_INVALID_HANDLE);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTCloseConnection(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles converting a Close Connection Request from an IRP to
+ a procedure call so that NbtCloseConnection can be called in an OS independent
+ manner.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+
+ TDI_REQUEST Request;
+ TDI_REQUEST_STATUS RequestStatus;
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS status;
+
+ CTEPagedCode();
+
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ Request.Handle.ConnectionContext = pIrpSp->FileObject->FsContext;
+
+ status = NbtCloseConnection(
+ &Request,
+ &RequestStatus,
+ pDeviceContext,
+ (PVOID)pIrp);
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NTSetFileObjectContexts(
+ IN PIRP pIrp,
+ IN PVOID FsContext,
+ IN PVOID FsContext2)
+
+/*++
+Routine Description:
+
+ This Routine handles fills in two context values in the Irp stack location,
+ that has to be done in an OS-dependent manner. This routine is called
+ from NbtOpenAddress() when a name is being registered on the network( i.e.
+ as a result of OpenAddress).
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+
+ PIO_STACK_LOCATION pIrpSp;
+ PFILE_OBJECT pFileObject;
+
+ //
+ // fill the IRP with context information so we can
+ // find the address object given the fileObject later.
+ //
+ // This must be done here, rather than after the call to NbtOpenAddress
+ // because that call can complete the Irp before it returns. Soooo,
+ // in the complete routine for the Irp, if the completion code is not
+ // good, it Nulls these two context values.
+ //
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pFileObject = pIrpSp->FileObject;
+ pFileObject->FsContext = FsContext;
+ pFileObject->FsContext2 =FsContext2;
+
+
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+NTClearFileObjectContext(
+ IN PIRP pIrp
+ )
+/*++
+Routine Description:
+
+ This Routine clears the context value in the file object when an address
+ object is closed.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ none
+
+--*/
+
+{
+
+ PIO_STACK_LOCATION pIrpSp;
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ CHECK_PTR(pIrpSp->FileObject);
+ pIrpSp->FileObject->FsContext = NULL;
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTSetSharedAccess(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp,
+ IN tADDRESSELE *pAddress)
+
+/*++
+Routine Description:
+
+ This Routine handles setting the shared access on the file object.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+
+ PACCESS_STATE AccessState;
+ ULONG DesiredAccess;
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS status;
+ static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+ CTEPagedCode();
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ if ((pIrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (pIrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE))
+ DesiredAccess = (ULONG)FILE_SHARE_READ;
+
+ else
+ DesiredAccess = (ULONG)0;
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredAccess,
+ pIrpSp->FileObject,
+ &pAddress->ShareAccess);
+
+ // assign the security descriptor ( need to to do this with the spinlock
+ // released because the descriptor is not mapped. Assign and CheckAccess
+ // are synchronized using a Resource.
+
+ AccessState = pIrpSp->Parameters.Create.SecurityContext->AccessState;
+
+
+ status = SeAssignSecurity(
+ NULL, // Parent Descriptor
+ AccessState->SecurityDescriptor,
+ &pAddress->SecurityDescriptor,
+ FALSE, // is a directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status))
+ {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (pIrpSp->FileObject, &pAddress->ShareAccess);
+
+ }
+ return status;
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTCheckSharedAccess(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp,
+ IN tADDRESSELE *pAddress)
+
+/*++
+Routine Description:
+
+ This Routine handles setting the shared access on the file object.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ ULONG DesiredAccess;
+ PIO_STACK_LOCATION pIrpSp;
+ BOOLEAN duplicate=FALSE;
+ NTSTATUS status;
+ ULONG DesiredShareAccess;
+ static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+ CTEPagedCode();
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+
+ if ((pIrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (pIrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE))
+ DesiredAccess = (ULONG)FILE_SHARE_READ;
+ else
+ DesiredAccess = (ULONG)0;
+
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+ AccessState = pIrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = STATUS_SUCCESS;
+
+ // *TODO* check that this routine is doing the right thing...
+ //
+ AccessAllowed = SeAccessCheck(
+ pAddress->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ pIrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ pIrp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+
+ // use the status from the IoCheckShareAccess as the return access
+ // event if SeAccessCheck fails....
+
+ //
+ // BUGBUG: Compare DesiredAccess to GrantedAccess?
+ //
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((pIrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (pIrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ //ACQUIRE_SPIN_LOCK (&pDeviceContext->SpinLock, &oldirql);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredAccess,
+ pIrpSp->FileObject,
+ &pAddress->ShareAccess,
+ TRUE);
+
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTCleanUpAddress(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles the first stage of releasing an address object.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ tCLIENTELE *pClientEle;
+ PIO_STACK_LOCATION pIrpSp;
+
+
+ CTEPagedCode();
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Cleanup Address Hit ***\n"));
+
+ //
+ // Disconnect any active connections, and for each connection that is not
+ // in use, remove one from the free list to the transport below.
+ //
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pClientEle = (tCLIENTELE *)pIrpSp->FileObject->FsContext;
+ CTEVerifyHandle(pClientEle,NBT_VERIFY_CLIENT,tCLIENTELE,&status);
+
+ status = NbtCleanUpAddress(pClientEle,pDeviceContext);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTCleanUpConnection(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles running down a connection in preparation for a close
+ that will come in next. NtClose hits this entry first, and then it hits
+ the NTCloseConnection next. If the connection was outbound, then the
+ address object must be closed as well as the connection. This routine
+ mainly deals with the pLowerconn connection to the transport whereas
+ NbtCloseConnection deals with closing pConnEle, the connection to the client.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION pIrpSp;
+ tCONNECTELE *pConnEle;
+
+ CTEPagedCode();
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
+
+#if DBG
+ if ((pConnEle->Verify != NBT_VERIFY_CONNECTION) &&
+ (pConnEle->Verify != NBT_VERIFY_CONNECTION_DOWN))
+ {
+ ASSERTMSG("Invalid Connection Handle passed to NtCleanupConnection\n",0);
+ return(STATUS_INVALID_HANDLE);
+ }
+#endif
+
+ //CTEVerifyHandle(pConnEle,NBT_VERIFY_CONNECTION,tCONNECTELE,&status);
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Cleanup Connection Hit state= %X\n",pConnEle->state));
+
+ status = NbtCleanUpConnection(pConnEle,pDeviceContext);
+
+ return(status);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTAccept(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles passing an accept for an inbound connect indication to
+ the OS independent code.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ TDI_REQUEST TdiRequest;
+ PIO_STACK_LOCATION pIrpSp;
+ PTDI_REQUEST_KERNEL_ACCEPT pRequest;
+
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt: ** Got an Accept from the Client **\n"));
+
+ // pull the junk out of the Irp and call the non-OS specific routine.
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ // the Parameters value points to a Request structure...
+ pRequest = (PTDI_REQUEST_KERNEL_ACCEPT)&pIrpSp->Parameters;
+
+ // the pConnEle ptr was stored in the FsContext value when the connection
+ // was initially created.
+ TdiRequest.Handle.ConnectionContext = pIrpSp->FileObject->FsContext;
+
+
+ status = NbtAccept(
+ &TdiRequest,
+ pRequest->RequestConnectionInformation,
+ pRequest->ReturnConnectionInformation,
+ pIrp);
+
+ return(status);
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTDisAssociateAddress(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+
+{
+ NTSTATUS status;
+ TDI_REQUEST TdiRequest;
+ PIO_STACK_LOCATION pIrpSp;
+ PTDI_REQUEST_KERNEL_ACCEPT pRequest;
+
+
+ CTEPagedCode();
+
+ // pull the junk out of the Irp and call the non-OS specific routine.
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ // the Parameters value points to a Request structure...
+ pRequest = (PTDI_REQUEST_KERNEL_ACCEPT)&pIrpSp->Parameters;
+
+ // the pConnEle ptr was stored in the FsContext value when the connection
+ // was initially created.
+ TdiRequest.Handle.ConnectionContext = pIrpSp->FileObject->FsContext;
+
+ status = NbtDisassociateAddress(&TdiRequest);
+
+ return(status);
+
+
+}
+
+NTSTATUS
+NbtpConnectCompletionRoutine(
+ PDEVICE_OBJECT pDeviceObject,
+ PIRP pIrp,
+ PVOID pCompletionContext)
+
+/*++
+Routine Description:
+
+ This Routine is the completion routine for local IRPS that are generated
+ to handle compound transport addresses
+
+Arguments:
+
+ pDeviceObject - the device object
+
+ pIrp - a ptr to an IRP
+
+ pCompletionContext - the completion context
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ KEVENT *pEvent = pCompletionContext;
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT: Completing local irp %lx\n",pIrp));
+ KeSetEvent((PKEVENT )pEvent, 0, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTConnect(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles calling the non OS specific code to open a session
+ connection to a destination.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ TDI_REQUEST Request;
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS Status;
+ PTDI_REQUEST_KERNEL pRequestKernel;
+ PTDI_CONNECTION_INFORMATION pRequestConnectionInformation;
+ PTRANSPORT_ADDRESS pRemoteAddress;
+ tCONNECTELE *pConnEle;
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pRequestKernel = (PTDI_REQUEST_KERNEL)&pIrpSp->Parameters;
+
+ Request.Handle.ConnectionContext = pIrpSp->FileObject->FsContext;
+ pConnEle = Request.Handle.ConnectionContext;
+
+ pRequestConnectionInformation = pRequestKernel->RequestConnectionInformation;
+ pRemoteAddress = pRequestConnectionInformation->RemoteAddress;
+
+ if (pRequestConnectionInformation->RemoteAddressLength < sizeof(TRANSPORT_ADDRESS)) {
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // The round about path of creating a Local IRP and processing the request is taken if
+ // we are either presented with a compound address, i.e., a transport address having
+ // multiple TA_ADDRESSes or if it is not a locally generated IRP(completion routine check)
+ // and the address type is not TDI_ADDRESS_TYPE_NETBIOS.
+ //
+ if ((pRemoteAddress->TAAddressCount > 1) ||
+ ((pIrpSp->CompletionRoutine != NbtpConnectCompletionRoutine) &&
+ (pRemoteAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_NETBIOS))) {
+ PIRP pLocalIrp;
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT: Taking the roundabout path\n"));
+
+ pLocalIrp = IoAllocateIrp(pDeviceContext->DeviceObject.StackSize,FALSE);
+ if (pLocalIrp != NULL) {
+ TDI_CONNECTION_INFORMATION LocalConnectionInformation;
+ PTRANSPORT_ADDRESS pTransportAddress;
+ PCHAR pTaAddress;
+ USHORT TaAddressLength,TransportAddressLength,AddressIndex;
+ USHORT TaAddressType;
+ KEVENT IrpCompletionEvent;
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT: Allocated local irp %lx\n",pLocalIrp));
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT: Compound Transport address %lx Count %lx\n",pRemoteAddress,pRemoteAddress->TAAddressCount));
+
+ TaAddressLength = 0;
+ pTaAddress = (PCHAR)&pRemoteAddress->Address[0] - FIELD_OFFSET(TA_ADDRESS,Address);
+
+ for (AddressIndex = 0;
+ AddressIndex < pRemoteAddress->TAAddressCount;
+ AddressIndex++) {
+ pTaAddress = (pTaAddress + TaAddressLength + FIELD_OFFSET(TA_ADDRESS,Address));
+
+ RtlCopyMemory(
+ &TaAddressLength,
+ (pTaAddress + FIELD_OFFSET(TA_ADDRESS,AddressLength)),
+ sizeof(USHORT));
+
+ RtlCopyMemory(
+ &TaAddressType,
+ (pTaAddress + FIELD_OFFSET(TA_ADDRESS,AddressType)),
+ sizeof(USHORT));
+
+ if (pConnEle->RemoteNameDoesNotExistInDNS) {
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("Skipping address type %lx length %lx for nonexistent name, pIrp %lx\n",TaAddressType,TaAddressLength,pIrp));
+
+ // If the address type is such that we rely on DNS name resolution and
+ // if a prior attempt failed, there is no point in reissuing the request.
+ // We can fail them without having to go on the NET.
+ switch (TaAddressType) {
+ case TDI_ADDRESS_TYPE_NETBIOS:
+ if (TaAddressLength == TDI_ADDRESS_LENGTH_NETBIOS) {
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ // lack of break intentional.
+ case TDI_ADDRESS_TYPE_NETBIOS_EX:
+ Status = STATUS_BAD_NETWORK_PATH;
+ break;
+ default:
+ Status = STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ if (Status != STATUS_SUCCESS) {
+ continue;
+ }
+ }
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT: pTaAddress %lx TaAddressLength %lx\n",pTaAddress,TaAddressLength));
+
+ // Allocate a buffer for copying the address and building a TRANSPORT_ADDRESS
+ // data structure.
+ TransportAddressLength = FIELD_OFFSET(TRANSPORT_ADDRESS,Address) +
+ FIELD_OFFSET(TA_ADDRESS,Address) +
+ TaAddressLength;
+
+ pTransportAddress = NbtAllocMem(TransportAddressLength,NBT_TAG('b'));
+ if (pTransportAddress == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ pTransportAddress->TAAddressCount = 1;
+
+ KeInitializeEvent(&IrpCompletionEvent, NotificationEvent, FALSE);
+
+ RtlCopyMemory(
+ &pTransportAddress->Address[0],
+ pTaAddress,
+ (TaAddressLength + FIELD_OFFSET(TA_ADDRESS,Address)));
+
+ pConnEle->AddressType = pTransportAddress->Address[0].AddressType;
+
+ LocalConnectionInformation = *(pRequestKernel->RequestConnectionInformation);
+ LocalConnectionInformation.RemoteAddress = pTransportAddress;
+ LocalConnectionInformation.RemoteAddressLength = TransportAddressLength;
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT: Building Connect Irp %lx\n",pLocalIrp));
+
+ TdiBuildConnect(
+ pLocalIrp,
+ &pDeviceContext->DeviceObject,
+ pIrpSp->FileObject,
+ NbtpConnectCompletionRoutine,
+ &IrpCompletionEvent,
+ pRequestKernel->RequestSpecific,
+ &LocalConnectionInformation,
+ pRequestKernel->ReturnConnectionInformation);
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("Local IoCallDriver Invoked %lx %lx\n",pLocalIrp,pIrp));
+
+ Status = IoCallDriver(&pDeviceContext->DeviceObject,pLocalIrp);
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT: IoCallDriver returned %lx\n",Status));
+
+ if (Status == STATUS_PENDING) {
+ // Await the completion of the Irp.
+ Status = KeWaitForSingleObject(&IrpCompletionEvent, // Object to wait on.
+ Executive, // Reason for waiting
+ KernelMode, // Processor mode
+ FALSE, // Alertable
+ NULL); // Timeout
+
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT: KeWiatForSingleObject returned %lx\n",Status));
+
+ // retrieve the completion status from the IRP. if it was successful exit,
+ // otherwise proceed to the next TA_ADDRESS in the transport address data
+ // structure.
+ Status = pLocalIrp->IoStatus.Status;
+ }
+
+ if (Status != STATUS_SUCCESS) {
+ // Ensure that the original IRP was not cancelled before continuing.
+ IoAcquireCancelSpinLock(&pIrp->CancelIrql);
+
+ if (pIrp->Cancel)
+ {
+ Status = STATUS_CANCELLED;
+ }
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ }
+
+ if (pTransportAddress != NULL) {
+ CTEFreeMem(pTransportAddress);
+ }
+
+ if ((Status == STATUS_SUCCESS) ||
+ (Status == STATUS_CANCELLED)) {
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT: exiting because of cancellation or success %lx\n",Status));
+ break;
+ } else {
+ IF_DBG(NBT_DEBUG_NETBIOS_EX)
+ KdPrint(("NETBT: trying next component because of failure %lx\n",Status));
+ }
+ }
+
+ IoFreeIrp(pLocalIrp);
+ } else {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ } else {
+ // call the non-NT specific function to setup the connection
+ Status = NbtConnect(
+ &Request,
+ pRequestKernel->RequestSpecific, // Ulong
+ pRequestKernel->RequestConnectionInformation,
+ pRequestKernel->ReturnConnectionInformation,
+ pIrp
+ );
+ }
+
+ return(Status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTDisconnect(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles calling the Non OS specific code to disconnect a
+ session.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ TDI_REQUEST Request;
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL pRequestKernel;
+
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pRequestKernel = (PTDI_REQUEST_KERNEL)&pIrpSp->Parameters;
+
+ Request.Handle.ConnectionContext = pIrpSp->FileObject->FsContext;
+
+ // call the non-NT specific function to setup the connection
+ status = NbtDisconnect(
+ &Request,
+ pRequestKernel->RequestSpecific, // Large Integer
+ pRequestKernel->RequestFlags,
+ pRequestKernel->RequestConnectionInformation,
+ pRequestKernel->ReturnConnectionInformation,
+ pIrp
+ );
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTListen(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+
+ NTSTATUS status;
+ TDI_REQUEST Request;
+ PTDI_REQUEST_KERNEL pRequestKernel;
+ PIO_STACK_LOCATION pIrpSp;
+
+ CTEPagedCode();
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got a LISTEN !!! *****************\n"));
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pRequestKernel = (PTDI_REQUEST_KERNEL)&pIrpSp->Parameters;
+
+ Request.Handle.ConnectionContext = pIrpSp->FileObject->FsContext;
+
+ // call the non-NT specific function to setup the connection
+ status = NbtListen(
+ &Request,
+ pRequestKernel->RequestFlags, // Ulong
+ pRequestKernel->RequestConnectionInformation,
+ pRequestKernel->ReturnConnectionInformation,
+ pIrp
+ );
+
+
+ if (status != STATUS_PENDING)
+ {
+ NTIoComplete(pIrp,status,0);
+ }
+ return(status);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+NbtCancelListen(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a listen Irp. It must release the
+ cancel spin lock before returning re: IoCancelIrp().
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ tCONNECTELE *pConnEle;
+ tCLIENTELE *pClientEle;
+ KIRQL OldIrq;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PIO_STACK_LOCATION pIrpSp;
+ tLISTENREQUESTS *pListenReq;
+
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got a LISTEN Cancel !!! *****************\n"));
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
+
+ pClientEle = pConnEle->pClientEle;
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+
+ // now search the client's listen queue looking for this connection
+ //
+ CTESpinLock(pClientEle,OldIrq);
+
+ pHead = &pClientEle->ListenHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pListenReq = CONTAINING_RECORD(pEntry,tLISTENREQUESTS,Linkage);
+ if ((pListenReq->pConnectEle == pConnEle) &&
+ (pListenReq->pIrp == pIrp))
+ {
+ RemoveEntryList(pEntry);
+ // complete the irp
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+
+
+ CTESpinFree(pClientEle,OldIrq);
+
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ CTEMemFree((PVOID)pListenReq);
+
+ return;
+
+ }
+ pEntry = pEntry->Flink;
+
+ }
+
+
+ CTESpinFree(pClientEle,OldIrq);
+
+
+ return;
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NTCancelSession(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a connect Irp. It must release the
+ cancel spin lock before returning re: IoCancelIrp(). It is called when
+ the session setup pdu has been sent, and the state is still outbound.
+
+ The cancel routine is only setup when the timer is started to time
+ sending the session response pdu.
+
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ tCONNECTELE *pConnEle;
+ KIRQL OldIrq;
+ PIO_STACK_LOCATION pIrpSp;
+ BOOLEAN DerefConnEle=FALSE;
+ tTIMERQENTRY *pTimer;
+ tDGRAM_SEND_TRACKING *pTracker;
+ COMPLETIONCLIENT pCompletion;
+ COMPLETIONROUTINE pCompletionRoutine;
+ PVOID pContext;
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got a Connect Irp Cancel !!! *****************\n"));
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+#ifdef RASAUTODIAL
+ //
+ // Cancel the automatic connection if one's
+ // in progress. If we don't find the
+ // connection block in the automatic
+ // connection driver, then it's already
+ // been completed.
+ //
+ if (pConnEle->fAutoConnecting) {
+ if (!NbtCancelPostConnect(pIrp))
+ return;
+ }
+#endif // RASAUTODIAL
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // the irp could get completed between calling this cancel routine
+ // and this point in the code
+ //
+ if (pConnEle->pIrp)
+ {
+ pTracker = (tDGRAM_SEND_TRACKING *)pConnEle->pIrpRcv;
+ if (pTracker)
+ {
+ pTimer = pTracker->Connect.pTimer;
+ pTracker->Connect.pTimer = NULL;
+ pTracker->Flags |= TRACKER_CANCELLED;
+
+ if (pTimer)
+ {
+ //
+ // stop the timer and only continue if the timer was stopped before
+ // it expired
+ //
+ pCompletionRoutine = pTimer->CompletionRoutine;
+ StopTimer(pTimer,&pCompletion,&pContext);
+
+ if (pCompletion)
+ {
+
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ (*pCompletionRoutine)(pTracker,(PVOID)STATUS_CANCELLED,pTimer);
+
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ else
+ if (pConnEle->state == NBT_SESSION_OUTBOUND)
+ {
+ //
+ // for some reason there is no timer, but the connection is still
+ // outbound, so call the timer completion routine to kill off
+ // the connection.
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ SessionTimedOut(pTracker,(PVOID)STATUS_CANCELLED,(PVOID)1);
+ } else {
+ //
+ // Free the lock
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return;
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+CheckAddrIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a DNS name query Irp that is passed
+ down to NBT from Lmhsvc, for the purpose of resolving a name with DNS.
+ Nbt will complete this irp each time it has a name to resolve with DNS.
+
+ This routine will get the Resource Lock, and Null the Irp ptr in the
+ DnsQueries structure and then return the irp.
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ BOOLEAN DerefConnEle=FALSE;
+ KIRQL OldIrq;
+
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got a Dns Irp Cancel !!! *****************\n"));
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (CheckAddr.QueryIrp)
+ {
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ CheckAddr.QueryIrp = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+
+ return;
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+DnsIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a DNS name query Irp that is passed
+ down to NBT from Lmhsvc, for the purpose of resolving a name with DNS.
+ Nbt will complete this irp each time it has a name to resolve with DNS.
+
+ This routine will get the Resource Lock, and Null the Irp ptr in the
+ DnsQueries structure and then return the irp.
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ BOOLEAN DerefConnEle=FALSE;
+ KIRQL OldIrq;
+
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got a Dns Irp Cancel !!! *****************\n"));
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (DnsQueries.QueryIrp)
+ {
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ DnsQueries.QueryIrp = NULL;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+ }
+ else
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+
+ return;
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+DiscWaitCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a Disconnect Wait Irp - which has
+ been passed down by a client so that when a disconnect occurs this
+ irp will complete and inform the client. The action here is to simply
+ complete the irp with status cancelled.
+ down to NBT from Lmhsvc, for the purpose of resolving a name with DNS.
+ Nbt will complete this irp each time it has a name to resolve with DNS.
+
+ This routine will get the Resource Lock, and Null the Irp ptr in the
+ DnsQueries structure and then return the irp.
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ tCONNECTELE *pConnEle;
+ PIO_STACK_LOCATION pIrpSp;
+ CTELockHandle OldIrq;
+
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got a Disc Wait Irp Cancel !!! *****************\n"));
+
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ CTESpinLock(pConnEle,OldIrq);
+
+ if (pConnEle->pIrpClose == pIrp)
+ {
+ pConnEle->pIrpClose = NULL;
+ }
+
+ CTESpinFree(pConnEle,OldIrq);
+
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ return;
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+WaitForDnsIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a Query to DNS, so that the client's
+ irp can be returned to the client. This cancellation is instigated
+ by the client (i.e. RDR).
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ BOOLEAN FoundIt = FALSE;
+ NBT_WORK_ITEM_CONTEXT *Context;
+ CTELockHandle OldIrq;
+ tDGRAM_SEND_TRACKING *pTracker;
+ PVOID pClientCompletion;
+ PVOID pClientContext;
+
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got a Wait For Dns Irp Cancel !!! *****************\n"));
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ Context = DnsIrpCancelPaged(DeviceContext,pIrp);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // Now complete the clients request to return the irp to the client
+ //
+ if (Context)
+ {
+ //
+ // this is the name Query tracker
+ //
+ pTracker = Context->pTracker;
+ pClientCompletion = Context->ClientCompletion;
+ pClientContext = Context->pClientContext;
+
+ // for dns names (NameLen>16), pTracker would be NULL
+ if (pTracker)
+ {
+ // name did not resolve, so delete from table
+ RemoveName(pTracker->pNameAddr);
+
+ DereferenceTracker(pTracker);
+ }
+
+ //
+ // this should complete any name queries that are waiting on
+ // this first name query - i.e. queries to the resolving name
+ //
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ STATUS_CANCELLED);
+
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ NBT_WORK_ITEM_CONTEXT *
+FindCheckAddrIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a Query to LmHost, so that the client's
+ irp can be returned to the client. This cancellation is instigated
+ by the client (i.e. RDR).
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ NBT_WORK_ITEM_CONTEXT *Context;
+ BOOLEAN FoundIt = FALSE;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ if (CheckAddr.ResolvingNow && CheckAddr.Context)
+ {
+ // this is the session setup tracker
+ //
+ pTracker = (tDGRAM_SEND_TRACKING *)((NBT_WORK_ITEM_CONTEXT *)CheckAddr.Context)->pClientContext;
+ if (pTracker->pClientIrp == pIrp)
+ {
+
+ Context = (NBT_WORK_ITEM_CONTEXT *)CheckAddr.Context;
+ CheckAddr.Context = NULL;
+ FoundIt = TRUE;
+
+ }
+ }
+ else
+ {
+ //
+ // go through the list of Queued requests to find the correct one
+ // and cancel it
+ //
+ pHead = pEntry = &CheckAddr.ToResolve;
+
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ Context = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
+
+ // this is the session setup tracker
+ //
+ pTracker = (tDGRAM_SEND_TRACKING *)Context->pClientContext;
+ if (pTracker->pClientIrp == pIrp)
+ {
+ RemoveEntryList(pEntry);
+ FoundIt = TRUE;
+ break;
+
+ }
+ }
+ }
+
+ return( FoundIt ? Context : NULL );
+}
+
+//----------------------------------------------------------------------------
+ NBT_WORK_ITEM_CONTEXT *
+LmHostIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a Query to LmHost, so that the client's
+ irp can be returned to the client. This cancellation is instigated
+ by the client (i.e. RDR).
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ NBT_WORK_ITEM_CONTEXT *Context;
+ BOOLEAN FoundIt = FALSE;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ if (LmHostQueries.ResolvingNow && LmHostQueries.Context)
+ {
+ // this is the session setup tracker
+ //
+ pTracker = (tDGRAM_SEND_TRACKING *)((NBT_WORK_ITEM_CONTEXT *)LmHostQueries.Context)->pClientContext;
+ if (pTracker->pClientIrp == pIrp)
+ {
+
+ Context = (NBT_WORK_ITEM_CONTEXT *)LmHostQueries.Context;
+ LmHostQueries.Context = NULL;
+ FoundIt = TRUE;
+
+ }
+ }
+ else
+ {
+ //
+ // go through the list of Queued requests to find the correct one
+ // and cancel it
+ //
+ pHead = pEntry = &LmHostQueries.ToResolve;
+
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ Context = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
+
+ // this is the session setup tracker
+ //
+ pTracker = (tDGRAM_SEND_TRACKING *)Context->pClientContext;
+ if (pTracker->pClientIrp == pIrp)
+ {
+ RemoveEntryList(pEntry);
+ FoundIt = TRUE;
+ break;
+
+ }
+ }
+ }
+
+ return( FoundIt ? Context : NULL );
+}
+
+//----------------------------------------------------------------------------
+ NBT_WORK_ITEM_CONTEXT *
+DnsIrpCancelPaged(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a Query to DNS, so that the client's
+ irp can be returned to the client. This cancellation is instigated
+ by the client (i.e. RDR).
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pClientTracker;
+ NBT_WORK_ITEM_CONTEXT *Context;
+ BOOLEAN FoundIt = FALSE;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ //
+ // First check the lmhost list, then the Dns list
+ //
+ Context = LmHostIrpCancel(DeviceContext,pIrp);
+
+ if (!Context)
+ {
+
+ Context = FindCheckAddrIrpCancel(DeviceContext,pIrp);
+
+ if (!Context)
+ {
+
+ if (DnsQueries.ResolvingNow && DnsQueries.Context)
+ {
+ //
+ // this is the session setup tracker
+ //
+ pClientTracker = (tDGRAM_SEND_TRACKING *)((NBT_WORK_ITEM_CONTEXT *)DnsQueries.Context)->pClientContext;
+ if (pClientTracker->pClientIrp == pIrp)
+ {
+
+ Context = (NBT_WORK_ITEM_CONTEXT *)DnsQueries.Context;
+ DnsQueries.Context = NULL;
+ FoundIt = TRUE;
+
+ }
+ }
+ else
+ {
+ //
+ // go through the list of Queued requests to find the correct one
+ // and cancel it
+ //
+ pHead = &DnsQueries.ToResolve;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ Context = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
+
+ // this is the session setup tracker
+ //
+ pClientTracker = (tDGRAM_SEND_TRACKING *)Context->pClientContext;
+ if (pClientTracker->pClientIrp == pIrp)
+ {
+ RemoveEntryList(pEntry);
+ FoundIt = TRUE;
+ break;
+
+ }
+ pEntry = pEntry->Flink;
+ }
+ }
+ } else {
+
+ // IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Found tracker in CheckAddr list: %lx\n", Context));
+ FoundIt = TRUE;
+ }
+ }
+ else
+ {
+ FoundIt = TRUE;
+ }
+
+ return( FoundIt ? Context : NULL );
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+QueryProviderCompletion(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion event when the Query Provider
+ Information completes. This routine must decrement the MaxDgramSize
+ and max send size by the respective NBT header sizes.
+
+Arguments:
+
+ DeviceObject - unused.
+
+ Irp - Supplies Irp that the transport has finished processing.
+
+ Context - not used
+
+Return Value:
+
+ The final status from the operation (success or an exception).
+
+--*/
+{
+ PTDI_PROVIDER_INFO pProvider;
+ ULONG HdrSize;
+ ULONG SubnetAddr;
+ ULONG ThisSubnetAddr;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tDEVICECONTEXT *pDeviceContext;
+ tDEVICECONTEXT *pDevContext;
+
+
+ if (NT_SUCCESS(Irp->IoStatus.Status))
+ {
+ pProvider = (PTDI_PROVIDER_INFO)MmGetMdlVirtualAddress(Irp->MdlAddress);
+
+ if (pProvider->MaxSendSize > sizeof(tSESSIONHDR))
+ {
+ //
+ // Nbt has just a two byte + 1 bit session message length, so it
+ // can't have a send size larger than 1ffff
+ //
+ if (pProvider->MaxSendSize > (0x1FFFF + sizeof(tSESSIONHDR)))
+ {
+ pProvider->MaxSendSize = 0x1FFFF;
+ }
+ else
+ {
+ pProvider->MaxSendSize -= sizeof(tSESSIONHDR);
+ }
+ }
+ else
+ {
+ pProvider->MaxSendSize = 0;
+ }
+
+ // subtract the datagram hdr size and the scope size (times 2)
+ HdrSize = DGRAM_HDR_SIZE + (NbtConfig.ScopeLength << 1);
+
+ if (pProvider->MaxDatagramSize > HdrSize)
+ {
+ pProvider->MaxDatagramSize -= HdrSize;
+ if (pProvider->MaxDatagramSize > MAX_NBT_DGRAM_SIZE)
+ {
+ pProvider->MaxDatagramSize = MAX_NBT_DGRAM_SIZE;
+ }
+ }
+ else
+ {
+ pProvider->MaxDatagramSize = 0;
+ }
+
+
+ //
+ // Set the correct service flags to indicate what Netbt supports.
+ //
+ pProvider->ServiceFlags = TDI_SERVICE_MESSAGE_MODE |
+ TDI_SERVICE_CONNECTION_MODE |
+ TDI_SERVICE_CONNECTIONLESS_MODE |
+ TDI_SERVICE_ERROR_FREE_DELIVERY |
+ TDI_SERVICE_BROADCAST_SUPPORTED |
+ TDI_SERVICE_MULTICAST_SUPPORTED |
+ TDI_SERVICE_DELAYED_ACCEPTANCE |
+ TDI_SERVICE_ROUTE_DIRECTED;
+
+ pProvider->MinimumLookaheadData = 128;
+
+ //
+ // Check if any of the adapters with the same subnet address have
+ // the PointtoPoint bit set - and if so set it in the response.
+ //
+ pDeviceContext = (tDEVICECONTEXT *)DeviceContext;
+ SubnetAddr = pDeviceContext->IpAddress & pDeviceContext->SubnetMask;
+
+ pEntry = pHead = &NbtConfig.DeviceContexts;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+ ThisSubnetAddr = pDevContext->IpAddress & pDevContext->SubnetMask;
+
+ if ((SubnetAddr == ThisSubnetAddr) &&
+ (pDevContext->PointToPoint))
+ {
+ pProvider->ServiceFlags |= TDI_SERVICE_POINT_TO_POINT;
+ break;
+ }
+ }
+ }
+
+
+ //
+ // Must return a non-error status otherwise the IO system will not copy
+ // back into the users buffer.
+ //
+
+ return(STATUS_SUCCESS);
+
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTQueryInformation(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ PIO_STACK_LOCATION pIrpSp;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION Query;
+ NTSTATUS status;
+ NTSTATUS Locstatus;
+ PVOID pBuffer;
+ LONG Size ;
+ PTA_NETBIOS_ADDRESS BroadcastAddress;
+ ULONG AddressLength;
+ ULONG BytesCopied;
+ PDEVICE_OBJECT pDeviceObject;
+
+ //
+ // Should not be pageable since AFD can call us at raised Irql in case of AcceptEx.
+ //
+ // CTEPagedCode();
+
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ Query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&pIrpSp->Parameters;
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("the query type is %X\n",Query->QueryType));
+
+ switch( Query->QueryType)
+ {
+ case TDI_QUERY_BROADCAST_ADDRESS:
+
+ // the broadcast address is the netbios name "*0000000..."
+
+ BroadcastAddress = (PTA_NETBIOS_ADDRESS)NbtAllocMem(
+ sizeof(TA_NETBIOS_ADDRESS),NBT_TAG('b'));
+
+ if (!BroadcastAddress)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ AddressLength = sizeof(TA_NETBIOS_ADDRESS);
+
+ BroadcastAddress->TAAddressCount = 1;
+ BroadcastAddress->Address[0].AddressLength = NETBIOS_NAME_SIZE +
+ sizeof(USHORT);
+ BroadcastAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ BroadcastAddress->Address[0].Address[0].NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
+
+ // the broadcast address to NetBios is "* 000000...", an * followed
+ // by 15 zeroes.
+ CTEZeroMemory(BroadcastAddress->Address[0].Address[0].NetbiosName,
+ NETBIOS_NAME_SIZE);
+ BroadcastAddress->Address[0].Address[0].NetbiosName[0] = '*';
+
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)BroadcastAddress,
+ 0,
+ AddressLength,
+ pIrp->MdlAddress,
+ 0,
+ (PULONG)&pIrp->IoStatus.Information);
+
+ CTEMemFree((PVOID)BroadcastAddress);
+
+ break;
+
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ //
+ // Simply pass the Irp on by to the Transport, and let it
+ // fill in the provider info
+ //
+ if (StreamsStack)
+ {
+ TdiBuildQueryInformation(pIrp,
+ pDeviceContext->pDgramDeviceObject,
+ pDeviceContext->pDgramFileObject,
+ QueryProviderCompletion,
+ NULL,
+ TDI_QUERY_PROVIDER_INFO,
+ pIrp->MdlAddress);
+ }
+ else
+ {
+ TdiBuildQueryInformation(pIrp,
+ pDeviceContext->pControlDeviceObject,
+ pDeviceContext->pControlFileObject,
+ QueryProviderCompletion,
+ NULL,
+ TDI_QUERY_PROVIDER_INFO,
+ pIrp->MdlAddress);
+ }
+
+ CHECK_COMPLETION(pIrp);
+ status = IoCallDriver(pDeviceContext->pControlDeviceObject,pIrp);
+ //
+ // we must return the next drivers ret code back to the IO subsystem
+ //
+ return(status);
+
+ break;
+
+ case TDI_QUERY_ADAPTER_STATUS:
+
+ //
+ // check if it is a remote or local adapter status
+ //
+ if (Query->RequestConnectionInformation &&
+ Query->RequestConnectionInformation->RemoteAddress)
+ {
+ PCHAR pName;
+ ULONG lNameType;
+ ULONG NameLen;
+
+ //
+ //
+ // in case the call results in a name query on the wire...
+ //
+ IoMarkIrpPending(pIrp);
+
+ status = GetNetBiosNameFromTransportAddress(
+ Query->RequestConnectionInformation->RemoteAddress,
+ &pName,
+ &NameLen,
+ &lNameType);
+
+ if ( NT_SUCCESS(status) &&
+ (lNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) &&
+ (NameLen <= NETBIOS_NAME_SIZE))
+ {
+ status = NbtSendNodeStatus(pDeviceContext,
+ pName,
+ pIrp,
+ 0,
+ 0,
+ NodeStatusDone);
+ }
+
+ // only complete the irp (below) for failure status's
+ if (status == STATUS_PENDING)
+ {
+ return(status);
+ }
+ // the request has been satisfied, so unmark the pending
+ // since we will return the irp below
+ //
+ pIrpSp->Control &= ~SL_PENDING_RETURNED;
+ }
+ else
+ {
+ Size = MmGetMdlByteCount( pIrp->MdlAddress ) ;
+
+ // return an array of netbios names that are registered
+ status = NbtQueryAdapterStatus(pDeviceContext,
+ &pBuffer,
+ &Size);
+
+ }
+ break;
+
+
+
+
+ case TDI_QUERY_CONNECTION_INFO:
+ {
+ tCONNECTELE *pConnectEle;
+ tLOWERCONNECTION *pLowerConn;
+
+ // pass to transport to get the current throughput, delay and
+ // reliability numbers
+ //
+
+ pConnectEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
+#if DBG
+ if (pConnectEle->Verify != NBT_VERIFY_CONNECTION)
+ {
+ status = STATUS_INVALID_HANDLE;
+ break;
+ }
+#endif
+ pLowerConn = (tLOWERCONNECTION *)pConnectEle->pLowerConnId;
+ if (!pLowerConn)
+ {
+ status = STATUS_CONNECTION_INVALID;
+ break;
+ }
+ //
+ // Simply pass the Irp on by to the Transport, and let it
+ // fill in the info
+ //
+ pDeviceObject = IoGetRelatedDeviceObject( pLowerConn->pFileObject );
+
+ TdiBuildQueryInformation(pIrp,
+ pDeviceObject,
+ pLowerConn->pFileObject,
+ NULL, NULL,
+ TDI_QUERY_CONNECTION_INFO,
+ pIrp->MdlAddress);
+
+
+ status = IoCallDriver(pDeviceObject,pIrp);
+
+ //
+ // we must return the next drivers ret code back to the IO subsystem
+ //
+ return(status);
+
+ break;
+ }
+
+ case TDI_QUERY_FIND_NAME:
+ //
+ //
+ // in case the call results in a name query on the wire...
+ //
+ IoMarkIrpPending(pIrp);
+ status = NbtQueryFindName(Query->RequestConnectionInformation,
+ pDeviceContext,
+ pIrp,
+ FALSE);
+
+ if (status == STATUS_PENDING)
+ {
+ return(status);
+ }
+
+ // the request has been satisfied, so unmark the pending
+ // since we will return the irp below
+ //
+ pIrpSp->Control &= ~SL_PENDING_RETURNED;
+
+ break;
+
+ case TDI_QUERY_ADDRESS_INFO:
+ status = NbtQueryGetAddressInfo(
+ pIrpSp,
+ &pBuffer,
+ &Size
+ );
+ break;
+
+ case TDI_QUERY_SESSION_STATUS:
+ default:
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt Query Info NOT SUPPORTED = %X\n",Query->QueryType));
+ status = STATUS_NOT_SUPPORTED;
+ break;
+
+ }
+
+ BytesCopied = 0;
+ if (!NT_ERROR(status) && // allow buffer overflow to pass by
+ ((Query->QueryType == TDI_QUERY_ADAPTER_STATUS) ||
+ (Query->QueryType == TDI_QUERY_ADDRESS_INFO)))
+ {
+ Locstatus = TdiCopyBufferToMdl(
+ pBuffer,
+ 0,
+ Size,
+ pIrp->MdlAddress,
+ 0,
+ &BytesCopied);
+
+ if (Locstatus == STATUS_BUFFER_OVERFLOW)
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ CTEMemFree((PVOID)pBuffer);
+ }
+ //
+ // either Success or an Error
+ // so complete the irp
+ //
+
+ NTIoComplete(pIrp,status,BytesCopied);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtQueryGetAddressInfo(
+ IN PIO_STACK_LOCATION pIrpSp,
+ OUT PVOID *ppBuffer,
+ OUT ULONG *pSize
+)
+{
+ NTSTATUS status;
+ BOOLEAN IsGroup;
+ PLIST_ENTRY p;
+ tADDRESSELE *pAddressEle;
+ tNAMEADDR *pNameAddr;
+ tADDRESS_INFO *pAddressInfo;
+ tCLIENTELE *pClientEle;
+ tCONNECTELE *pConnectEle;
+ CTELockHandle OldIrq;
+
+ pClientEle = pIrpSp->FileObject->FsContext;
+ if (pClientEle->Verify != NBT_VERIFY_CLIENT)
+ {
+ CTELockHandle OldIrq1;
+ pConnectEle = (tCONNECTELE *)pClientEle;
+
+ //
+ // We crashed here since the pLowerConn was NULL below.
+ // Check the state of the connection, since it is possible that the connection
+ // was aborted and the disconnect indicated, but this query came in before the client
+ // got the disconnect indication.
+ // If the state is idle (in case of TDI_DISCONNECT_ABORT) or DISCONNECTED
+ // (TDI_DISCONNECT_RELEASE), error out.
+ // Also check for NBT_ASSOCIATED.
+ //
+ // NOTE: If NbtOpenConnection is unable to allocate the lower conn block (say, if the session fileobj
+ // has not been created yet), the state will be still be IDLE, so we are covered here.
+ //
+ CTESpinLock(pConnectEle,OldIrq1);
+
+ if ((pConnectEle->Verify != NBT_VERIFY_CONNECTION) ||
+ (pConnectEle->state <= NBT_ASSOCIATED) || // includes NBT_IDLE
+ (pConnectEle->state == NBT_DISCONNECTED))
+ {
+ status = STATUS_INVALID_HANDLE;
+ }
+ else
+ {
+ //
+ // A TdiQueryInformation() call requesting TDI_QUERY_ADDRESS_INFO
+ // on a connection. Fill in a TDI_ADDRESS_INFO containing both the
+ // NetBIOS address and the IP address of the remote. Some of the
+ // fields are fudged.
+ //
+
+ PNBT_ADDRESS_PAIR_INFO pAddressPairInfo;
+ pAddressPairInfo = NbtAllocMem(sizeof (NBT_ADDRESS_PAIR_INFO), NBT_TAG('c'));
+
+ if (pAddressPairInfo)
+ {
+ memset ( pAddressPairInfo, 0, sizeof(NBT_ADDRESS_PAIR_INFO) );
+
+ pAddressPairInfo->ActivityCount = 1;
+
+ pAddressPairInfo->AddressPair.TAAddressCount = 2;
+
+ pAddressPairInfo->AddressPair.AddressNetBIOS.AddressLength =
+ TDI_ADDRESS_LENGTH_NETBIOS;
+
+ pAddressPairInfo->AddressPair.AddressNetBIOS.AddressType =
+ TDI_ADDRESS_TYPE_NETBIOS;
+
+ pAddressPairInfo->AddressPair.AddressNetBIOS.Address.NetbiosNameType =
+ TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+
+ memcpy( &pAddressPairInfo->AddressPair.AddressNetBIOS.Address.NetbiosName[0],
+ &pConnectEle->RemoteName[0],
+ 16
+ );
+
+ pAddressPairInfo->AddressPair.AddressIP.AddressLength =
+ TDI_ADDRESS_LENGTH_IP;
+
+ pAddressPairInfo->AddressPair.AddressIP.AddressType =
+ TDI_ADDRESS_TYPE_IP;
+
+ //
+ // Check for NULL (should not be NULL here since we check for states above).
+ //
+ // BUGBUG: Remove this check once we are sure that we are not hitting this condition
+ //
+ if (pConnectEle->pLowerConnId) {
+ pAddressPairInfo->AddressPair.AddressIP.Address.in_addr =
+ pConnectEle->pLowerConnId->SrcIpAddr;
+
+ *ppBuffer = (PVOID)pAddressPairInfo;
+ *pSize = sizeof(NBT_ADDRESS_PAIR_INFO);
+ status = STATUS_SUCCESS;
+ } else {
+ DbgPrint("pLowerConn NULL in pConnEle%lx, state: %lx\n", pConnectEle, pConnectEle->state);
+ status = STATUS_INVALID_HANDLE;
+ }
+ }
+ else
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ CTESpinFree(pConnectEle,OldIrq1);
+ }
+ else
+ {
+ pAddressInfo = NbtAllocMem(sizeof(tADDRESS_INFO),NBT_TAG('c'));
+ if (pAddressInfo)
+ {
+ //
+ // count the clients attached to this address
+ // We need to spinlock the address element, which
+ // is why this routine is not pageable
+ //
+ pAddressInfo->ActivityCount = 0;
+ pAddressEle = pClientEle->pAddress;
+
+ CTESpinLock(pAddressEle,OldIrq);
+
+ for (p = pAddressEle->ClientHead.Flink;
+ p != &pAddressEle->ClientHead;
+ p = p->Flink) {
+ ++pAddressInfo->ActivityCount;
+ }
+
+ CTESpinFree(pAddressEle,OldIrq);
+
+ pNameAddr = pAddressEle->pNameAddr;
+
+ IsGroup = (pNameAddr->NameTypeState & NAMETYPE_UNIQUE) ?
+ FALSE : TRUE;
+
+ TdiBuildNetbiosAddress((PUCHAR)pNameAddr->Name,
+ IsGroup,
+ &pAddressInfo->NetbiosAddress);
+
+ *ppBuffer = (PVOID)pAddressInfo;
+ *pSize = sizeof(tADDRESS_INFO);
+ status = STATUS_SUCCESS;
+
+ }
+ else
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ return status;
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+DispatchIoctls(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp,
+ IN PIO_STACK_LOCATION pIrpSp)
+
+/*++
+Routine Description:
+
+ This Routine handles calling the OS independent routine depending on
+ the Ioctl passed in.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status=STATUS_UNSUCCESSFUL;
+ NTSTATUS Locstatus;
+ ULONG ControlCode;
+ ULONG Size;
+ PVOID pBuffer;
+
+ CTEPagedCode();
+
+ ControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Ioctl Value is %X\n",ControlCode));
+
+ switch (ControlCode)
+ {
+ case IOCTL_NETBT_PURGE_CACHE:
+ {
+
+ status = NbtResyncRemoteCache();
+
+ break;
+ }
+ break;
+ case IOCTL_NETBT_GET_CONNECTIONS:
+ {
+ if (pIrp->MdlAddress)
+ {
+ Size = MmGetMdlByteCount( pIrp->MdlAddress ) ;
+
+ // return an array of netbios names that are registered
+ status = NbtQueryConnectionList(NULL,
+ &pBuffer,
+ &Size);
+ }
+ break;
+ }
+
+ case IOCTL_NETBT_ADAPTER_STATUS:
+
+ if (pIrp->MdlAddress)
+ {
+ PIO_STACK_LOCATION pIrpSp;
+ tIPANDNAMEINFO *pIpAndNameInfo;
+ PCHAR pName;
+ ULONG lNameType;
+ ULONG NameLen;
+ ULONG IpAddrsList[2];
+
+ //
+ // in case the call results in a name query on the wire...
+ //
+ IoMarkIrpPending(pIrp);
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pIpAndNameInfo = pIrp->AssociatedIrp.SystemBuffer;
+
+ // this routine gets a ptr to the netbios name out of the wierd
+ // TDI address syntax.
+ status = GetNetBiosNameFromTransportAddress(
+ &pIpAndNameInfo->NetbiosAddress,
+ &pName,
+ &NameLen,
+ &lNameType);
+
+ if ( NT_SUCCESS(status) &&
+ (lNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) &&
+ (NameLen <= NETBIOS_NAME_SIZE))
+ {
+ //
+ // Nbtstat sends down * in the first byte on Nbtstat -A <IP address>
+ // Make sure we let that case go ahead.
+ //
+ if ((pName[0] == '*') &&
+ (pIpAndNameInfo->IpAddress == 0)) {
+
+ status = STATUS_BAD_NETWORK_PATH;
+ } else {
+ IpAddrsList[0] = pIpAndNameInfo->IpAddress;
+ IpAddrsList[1] = 0;
+ status = NbtSendNodeStatus(pDeviceContext,
+ pName,
+ pIrp,
+ &IpAddrsList[0],
+ 0,
+ NodeStatusDone);
+ }
+
+ }
+ // only complete the irp (below) for failure status's
+ if (status == STATUS_PENDING)
+ {
+ return(status);
+ }
+ // the request has been satisfied, so unmark the pending
+ // since we will return the irp below
+ //
+ pIrpSp->Control &= ~SL_PENDING_RETURNED;
+
+ }
+ break;
+
+ case IOCTL_NETBT_GET_REMOTE_NAMES:
+
+ if (pIrp->MdlAddress)
+ {
+ Size = MmGetMdlByteCount( pIrp->MdlAddress ) ;
+
+ // return an array of netbios names that are registered
+ status = NbtQueryAdapterStatus(NULL,
+ &pBuffer,
+ &Size);
+ }
+ break;
+
+ case IOCTL_NETBT_GET_BCAST_NAMES:
+ {
+ if (pIrp->MdlAddress)
+ {
+ Size = MmGetMdlByteCount( pIrp->MdlAddress ) ;
+
+ // return an array of netbios names that are registered
+ status = NbtQueryBcastVsWins(pDeviceContext,&pBuffer,&Size);
+ }
+ break;
+ }
+
+ case IOCTL_NETBT_REREAD_REGISTRY:
+
+ status = NTReReadRegistry(pDeviceContext);
+
+ break;
+
+ case IOCTL_NETBT_ENABLE_EXTENDED_ADDR: {
+ //
+ // Enable extended addressing - pass up IP addrs on Datagram Recvs.
+ //
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (pIrp);
+ tCLIENTELE *pClientEle = (tCLIENTELE *)pIrpSp->FileObject->FsContext;
+
+ status = STATUS_SUCCESS;
+
+ if (pIrpSp->FileObject->FsContext2 != (PVOID)NBT_ADDRESS_TYPE) {
+ status = STATUS_INVALID_ADDRESS;
+ } else {
+ pClientEle->ExtendedAddress = TRUE;
+ }
+ break;
+ }
+
+ case IOCTL_NETBT_DISABLE_EXTENDED_ADDR: {
+ //
+ // Disnable extended addressing - dont pass up IP addrs on Datagram Recvs.
+ //
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (pIrp);
+ tCLIENTELE *pClientEle = (tCLIENTELE *)pIrpSp->FileObject->FsContext;
+
+ status = STATUS_SUCCESS;
+
+ if (pIrpSp->FileObject->FsContext2 != (PVOID)NBT_ADDRESS_TYPE) {
+ status = STATUS_INVALID_ADDRESS;
+ } else {
+ pClientEle->ExtendedAddress = FALSE;
+ }
+ break;
+ }
+
+ case IOCTL_NETBT_NEW_IPADDRESS:
+
+ {
+
+ tNEW_IP_ADDRESS *pNewAddress = (tNEW_IP_ADDRESS *)pIrp->AssociatedIrp.SystemBuffer;
+
+ status = NbtNewDhcpAddress(pDeviceContext,
+ pNewAddress->IpAddress,
+ pNewAddress->SubnetMask);
+
+ break;
+ }
+
+ case IOCTL_NETBT_ADD_INTERFACE:
+ //
+ // Creates a dummy devicecontext which can be primed by the layer above
+ // with a DHCP address. This is to support multiple IP addresses per adapter
+ // for the Clusters group; but can be used by any module that needs support
+ // for more than one IP address per adapter. This private interface hides the
+ // devices thus created from the setup/regisrty and that is fine since the
+ // component (say, the clusters client) takes the responsibility for ensuring
+ // that the server (above us) comes to know of this new device.
+ //
+ {
+
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (pIrp);
+ // IF_DBG(NBT_DEBUG_PNP_POWER)
+ KdPrint(("Ioctl Value is %X (IOCTL_NETBT_ADD_INTERFACE)\n",ControlCode));
+ pBuffer = pIrp->AssociatedIrp.SystemBuffer;
+ Size = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+ //
+ // return the export string created.
+ //
+ status = NbtAddNewInterface(pIrp, pBuffer, Size);
+
+ NTIoComplete(pIrp,status,(ULONG)-1);
+ return status;
+ }
+
+ case IOCTL_NETBT_DELETE_INTERFACE:
+ {
+#if 0
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (pIrp);
+ //
+ // Validate input buffer size
+ //
+ Size = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ if (Size < sizeof(NETBT_ADD_DEL_IF)) {
+ // IF_DBG(NBT_DEBUG_PNP_POWER)
+ KdPrint(("NbtAddNewInterface: Output buffer too small for struct\n"));
+ status = STATUS_INVALID_PARAMETER;
+ } else {
+ pBuffer = pIrp->AssociatedIrp.SystemBuffer;
+ status = NbtDestroyDeviceObject(pBuffer);
+ }
+#endif
+ //
+ // Delete the device this came down on..
+ //
+ ASSERT(!pDeviceContext->IsDestroyed);
+ ASSERT(pDeviceContext->IsDynamic);
+
+ status = NbtDestroyDeviceObject(pDeviceContext);
+
+ break;
+ }
+
+ case IOCTL_NETBT_QUERY_INTERFACE_INSTANCE:
+ {
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (pIrp);
+
+ //
+ // Validate input/output buffer size
+ //
+ Size = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+ if (Size < sizeof(NETBT_ADD_DEL_IF)) {
+ // IF_DBG(NBT_DEBUG_PNP_POWER)
+ KdPrint(("NbtQueryInstance: Output buffer too small for struct\n"));
+ status = STATUS_INVALID_PARAMETER;
+ } else {
+ PNETBT_ADD_DEL_IF pAddDelIf = (PNETBT_ADD_DEL_IF)pIrp->AssociatedIrp.SystemBuffer;
+ status = STATUS_SUCCESS;
+
+ ASSERT(pDeviceContext->IsDynamic);
+ pAddDelIf->InstanceNumber = pDeviceContext->InstanceNumber;
+ pAddDelIf->Status = status;
+ pIrp->IoStatus.Information = sizeof(NETBT_ADD_DEL_IF);
+
+ NTIoComplete(pIrp,status,(ULONG)-1);
+ return status;
+
+ }
+ break;
+ }
+
+ case IOCTL_NETBT_SET_WINS_ADDRESS: {
+ //
+ // Sets the WINS addresses for a dynamic adapter
+ //
+
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (pIrp);
+
+ //
+ // Validate input/output buffer size
+ //
+ Size = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ if (Size < sizeof(NETBT_SET_WINS_ADDR)) {
+ // IF_DBG(NBT_DEBUG_PNP_POWER)
+ KdPrint(("NbtSetWinsAddr: Input buffer too small for struct\n"));
+ status = STATUS_INVALID_PARAMETER;
+ } else {
+ PNETBT_SET_WINS_ADDR pSetWinsAddr = (PNETBT_SET_WINS_ADDR)pIrp->AssociatedIrp.SystemBuffer;
+ status = STATUS_SUCCESS;
+
+ ASSERT(pDeviceContext->IsDynamic);
+
+ pDeviceContext->lNameServerAddress = pSetWinsAddr->PrimaryWinsAddr;
+ pDeviceContext->lBackupServer = pSetWinsAddr->SecondaryWinsAddr;
+
+ pSetWinsAddr->Status = status;
+ pIrp->IoStatus.Information = sizeof(NETBT_SET_WINS_ADDR);
+
+ NTIoComplete(pIrp,status,(ULONG)-1);
+ return status;
+
+ }
+ }
+
+ case IOCTL_NETBT_DNS_NAME_RESOLVE:
+ {
+ if (pIrp->MdlAddress)
+ {
+ Size = MmGetMdlByteCount( pIrp->MdlAddress ) ;
+ pBuffer = MmGetSystemAddressForMdl(pIrp->MdlAddress);
+
+ // return an array of netbios names that are registered
+ status = NtDnsNameResolve(pDeviceContext,pBuffer,Size,pIrp);
+
+ return(status);
+ }
+ break;
+ }
+
+ case IOCTL_NETBT_CHECK_IP_ADDR: {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Ioctl Value is %X (IOCTL_NETBT_CHECK_IP_ADDR)\n",ControlCode));
+
+ if (pIrp->MdlAddress)
+ {
+ Size = MmGetMdlByteCount( pIrp->MdlAddress ) ;
+ pBuffer = MmGetSystemAddressForMdl(pIrp->MdlAddress);
+
+ // return an array of netbios names that are registered
+ status = NtCheckForIPAddr(pDeviceContext,pBuffer,Size,pIrp);
+
+ return(status);
+ }
+ break;
+ }
+
+ case IOCTL_NETBT_FIND_NAME:
+ {
+ tIPADDR_BUFFER *pIpAddrBuffer;
+
+ //
+ // in case the call results in a name query on the wire...
+ //
+ IoMarkIrpPending(pIrp);
+
+ pIpAddrBuffer = pIrp->AssociatedIrp.SystemBuffer;
+
+ status = NbtQueryFindName((PTDI_CONNECTION_INFORMATION)pIpAddrBuffer,
+ pDeviceContext,
+ pIrp,
+ TRUE);
+
+ if (status == STATUS_PENDING)
+ {
+ return(status);
+ }
+
+ // the request has been satisfied, so unmark the pending
+ // since we will return the irp below
+ //
+ pIrpSp->Control &= ~SL_PENDING_RETURNED;
+
+ break;
+ }
+
+ case IOCTL_NETBT_GET_WINS_ADDR:
+ {
+ if (pIrp->MdlAddress)
+ {
+ tWINS_ADDRESSES *pBuffer;
+
+ if( MmGetMdlByteCount( pIrp->MdlAddress ) >= sizeof(tWINS_ADDRESSES))
+ {
+ pBuffer = (tWINS_ADDRESSES *)MmGetSystemAddressForMdl(pIrp->MdlAddress);
+ pBuffer->PrimaryWinsServer = pDeviceContext->lNameServerAddress;
+ pBuffer->BackupWinsServer = pDeviceContext->lBackupServer;
+
+ status = STATUS_SUCCESS;
+ }
+ else
+ status = STATUS_BUFFER_OVERFLOW;
+
+ break;
+
+ }
+ break;
+ }
+
+ case IOCTL_NETBT_GET_IP_ADDRS:
+ {
+ ULONG Length;
+ PULONG pIpAddr;
+ PLIST_ENTRY pEntry,pHead;
+ tDEVICECONTEXT *pDevContext;
+
+ //
+ // return this devicecontext's ip address and all the other
+ // ip addrs after it.
+ //
+ if (pIrp->MdlAddress)
+ {
+ Length = MmGetMdlByteCount( pIrp->MdlAddress );
+
+ if (Length < sizeof(ULONG)) {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else {
+ //
+ // Put this adapter first in the list
+ //
+ pIpAddr = (PULONG )MmGetSystemAddressForMdl(pIrp->MdlAddress);
+ *pIpAddr = pDeviceContext->IpAddress;
+ pIpAddr++;
+ Length -= sizeof(ULONG);
+ status = STATUS_SUCCESS;
+
+ pEntry = pHead = &NbtConfig.DeviceContexts;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ if (Length < sizeof(ULONG)) {
+ status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ pDevContext = CONTAINING_RECORD(
+ pEntry,
+ tDEVICECONTEXT,
+ Linkage
+ );
+
+ if ((pDevContext != pDeviceContext) &&
+ (pDevContext->IpAddress))
+ {
+ *pIpAddr = pDevContext->IpAddress;
+ pIpAddr++;
+ Length -= sizeof(ULONG);
+ }
+ }
+
+ if (status == STATUS_SUCCESS) {
+ if (Length < sizeof(ULONG)) {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ else {
+ //
+ // put a 0 address on the end
+ //
+ *pIpAddr = 0;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+
+ case IOCTL_NETBT_GET_IP_SUBNET:
+ {
+ ULONG Length;
+ PULONG pIpAddr;
+
+ //
+ // return this devicecontext's ip address and all the other
+ // ip addrs after it.
+ //
+ if (pIrp->MdlAddress)
+ {
+ Length = MmGetMdlByteCount( pIrp->MdlAddress );
+ if (Length < 2*sizeof(ULONG))
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ //
+ // Put this adapter first in the list
+ //
+ pIpAddr = (PULONG )MmGetSystemAddressForMdl(pIrp->MdlAddress);
+ *pIpAddr = pDeviceContext->IpAddress;
+ pIpAddr++;
+ *pIpAddr = pDeviceContext->SubnetMask;
+
+ status = STATUS_SUCCESS;
+ }
+ }
+ }
+ break;
+
+ case IOCTL_NETBT_WINS_RCV:
+ {
+ if (pIrp->MdlAddress)
+ {
+ status = RcvIrpFromWins(pDeviceContext,pIrp);
+ return(status);
+
+ }
+ break;
+ }
+ case IOCTL_NETBT_WINS_SEND:
+ {
+ if (pIrp->MdlAddress)
+ {
+ BOOLEAN MustSend;
+
+ status = WinsSendDatagram(pDeviceContext,pIrp,(MustSend = FALSE));
+ return(status);
+
+ break;
+
+ }
+ break;
+ }
+
+ }
+
+ //
+ // copy the reponse to the client's Mdl
+ //
+ if (!NT_ERROR(status) && // allow buffer overflow to pass by
+ ((ControlCode == IOCTL_NETBT_GET_REMOTE_NAMES) ||
+ (ControlCode == IOCTL_NETBT_GET_BCAST_NAMES) ||
+ (ControlCode == IOCTL_NETBT_GET_CONNECTIONS)) )
+ {
+ Locstatus = TdiCopyBufferToMdl(
+ pBuffer,
+ 0,
+ Size,
+ pIrp->MdlAddress,
+ 0,
+ (PULONG)&pIrp->IoStatus.Information);
+
+ if (Locstatus == STATUS_BUFFER_OVERFLOW)
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ CTEMemFree((PVOID)pBuffer);
+ }
+ //
+ // either Success or an Error
+ // so complete the irp
+ //
+ NTIoComplete(pIrp,status,0);
+
+ return(status);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+NTCancelReceive(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a listen Irp. It must release the
+ cancel spin lock before returning re: IoCancelIrp().
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ tCONNECTELE *pConnEle;
+ tLOWERCONNECTION *pLowerConn;
+ KIRQL OldIrq;
+ KIRQL OldIrq1;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PIO_STACK_LOCATION pIrpSp;
+ PIRP pRcvIrp;
+
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got a Receive Cancel !!! *****************\n"));
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ pLowerConn = pConnEle->pLowerConnId;
+ if (pLowerConn)
+ {
+ CTESpinLock(pLowerConn,OldIrq);
+ }
+
+ if (pConnEle->Verify == NBT_VERIFY_CONNECTION)
+ {
+ // now search the connection's receive queue looking for this Irp
+ //
+ pHead = &pConnEle->RcvHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pRcvIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
+ if (pRcvIrp == pIrp)
+ {
+ RemoveEntryList(pEntry);
+
+ // complete the irp
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+
+ if (pLowerConn)
+ {
+ CTESpinFree(pLowerConn,OldIrq);
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ return;
+
+ }
+ pEntry = pEntry->Flink;
+
+ }
+
+ }
+
+ if (pLowerConn)
+ {
+ CTESpinFree(pLowerConn,OldIrq);
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ return;
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTReceive(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles Queuing a receive buffer on a connection or passing
+ the recieve buffer to the transport if there is outstanding data waiting
+ to be received on the connection.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status=STATUS_UNSUCCESSFUL;
+ PTDI_REQUEST_KERNEL pRequestKernel;
+ PIO_STACK_LOCATION pIrpSp;
+ tCONNECTELE *pConnEle;
+ KIRQL OldIrq;
+ ULONG ToCopy;
+ ULONG ClientRcvLen;
+ tLOWERCONNECTION *pLowerConn;
+ ULONG RemainingPdu;
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pRequestKernel = (PTDI_REQUEST_KERNEL)&pIrpSp->Parameters;
+
+ pConnEle = pIrpSp->FileObject->FsContext;
+
+ PUSH_LOCATION(0x30);
+
+ // be sure we have not been passed some bogus ptr
+ //
+#if DBG
+ if (pConnEle->Verify != NBT_VERIFY_CONNECTION)
+ {
+ status = STATUS_INVALID_HANDLE;
+ NTIoComplete(pIrp,status,0);
+ return(status);
+
+ }
+#endif
+ if (pConnEle->state == NBT_SESSION_UP)
+ {
+ PIO_STACK_LOCATION pIrpSp;
+ PTDI_REQUEST_KERNEL_RECEIVE pParams;
+ PTDI_REQUEST_KERNEL_RECEIVE pClientParams;
+ ULONG BytesCopied;
+
+ PUSH_LOCATION(0x31);
+
+ pLowerConn = pConnEle->pLowerConnId;
+
+ CTESpinLock(pLowerConn,OldIrq);
+
+ if (pLowerConn->StateRcv != PARTIAL_RCV)
+ {
+ // **** Fast Path Code ****
+ //
+ // Queue this receive buffer on to the Rcv Head
+ //
+ PUSH_LOCATION(0x46);
+ InsertTailList(&pConnEle->RcvHead,
+ &pIrp->Tail.Overlay.ListEntry);
+
+ status = NTCheckSetCancelRoutine(pIrp,(PVOID)NTCancelReceive,pDeviceContext);
+
+ if (!NT_SUCCESS(status))
+ {
+ RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
+ CTESpinFree(pLowerConn,OldIrq);
+ NTIoComplete(pIrp,status,0);
+ return(status);
+ }
+ else
+ {
+ //
+ // if the irp is not cancelled, returning pending
+ //
+ CTESpinFree(pLowerConn,OldIrq);
+ return(STATUS_PENDING);
+ }
+
+
+ }
+ else
+ {
+
+ // ***** Partial Rcv - Data Still in Transport *****
+
+ BOOLEAN ZeroLengthSend;
+
+ PUSH_LOCATION(0x32);
+
+ IF_DBG(NBT_DEBUG_RCV)
+ KdPrint(("Nbt:A Rcv Buffer posted data in Xport,InXport= %X,InIndic %X RcvIndicated %X\n",
+ pConnEle->BytesInXport,pLowerConn->BytesInIndicate,
+ pConnEle->ReceiveIndicated));
+
+
+ // get the MDL chain length
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pClientParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
+
+ // Reset the Irp pending flag
+ pIrpSp->Control &= ~SL_PENDING_RETURNED;
+
+ // fill in the next irp stack location with our completion routine.
+ pIrpSp = IoGetNextIrpStackLocation(pIrp);
+
+ pIrpSp->CompletionRoutine = CompletionRcv;
+ pIrpSp->Context = (PVOID)pConnEle->pLowerConnId;
+ pIrpSp->Flags = 0;
+
+ // set flags so the completion routine is always invoked.
+ pIrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
+
+ pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ pIrpSp->MinorFunction = TDI_RECEIVE;
+ pIrpSp->DeviceObject = IoGetRelatedDeviceObject(pConnEle->pLowerConnId->pFileObject);
+ pIrpSp->FileObject = pConnEle->pLowerConnId->pFileObject;
+
+ pParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
+ pParams->ReceiveFlags = pClientParams->ReceiveFlags;
+
+ // Since this irp is going to traverse through CompletionRcv, we
+ // need to set the following, since it undoes this stuff.
+ // This also prevents the LowerConn from being blown away before
+ // the irp has returned from the transport
+ //
+ pLowerConn->RefCount++;
+ //
+ // pass the receive buffer directly to the transport, decrementing
+ // the number of receive bytes that have been indicated
+ //
+ ASSERT(pConnEle->TotalPcktLen >= pConnEle->BytesRcvd);
+ if (pClientParams->ReceiveLength > (pConnEle->TotalPcktLen - pConnEle->BytesRcvd))
+ {
+ pParams->ReceiveLength = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
+ }
+ else
+ {
+ pParams->ReceiveLength = pClientParams->ReceiveLength;
+ }
+
+ ClientRcvLen = pParams->ReceiveLength;
+ //
+ // Set the amount of data that we will receive so when the
+ // irp completes in completionRcv, we can fill in that
+ // info in the Irp
+ //
+ pConnEle->CurrentRcvLen = ClientRcvLen;
+
+ // if a zero length send occurs, then ReceiveIndicated is set
+ // to zero with the state set to RcvPartial. Or, the client may
+ // pass down an Irp with no MDL in it!! - stupid but true
+ //
+ if ((pConnEle->ReceiveIndicated == 0) || !pIrp->MdlAddress)
+ {
+ ZeroLengthSend = TRUE;
+ }
+ else
+ ZeroLengthSend = FALSE;
+
+ // calculate how many bytes are still remaining for the client.
+ ASSERT(pConnEle->ReceiveIndicated <= 0x20000);
+ if (pConnEle->ReceiveIndicated > ClientRcvLen)
+ {
+ PUSH_LOCATION(0x40);
+ pConnEle->ReceiveIndicated -= ClientRcvLen;
+ }
+ else
+ {
+ pConnEle->ReceiveIndicated = 0;
+ }
+
+ if (pLowerConn->BytesInIndicate || ZeroLengthSend)
+ {
+ PMDL Mdl;
+
+ PUSH_LOCATION(0x33);
+ if (ClientRcvLen > pLowerConn->BytesInIndicate)
+ {
+ ToCopy = pLowerConn->BytesInIndicate;
+ }
+ else
+ {
+ PUSH_LOCATION(0x41);
+ ToCopy = ClientRcvLen;
+ }
+
+ // copy data from the indicate buffer to the client's buffer,
+ // remembering that there is a session header in the indicate
+ // buffer at the start of it... so skip that. The
+ // client can pass down a null Mdl address for a zero length
+ // rcv so check for that.
+ //
+ Mdl = pIrp->MdlAddress;
+
+ if (Mdl)
+ {
+ TdiCopyBufferToMdl(MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl),
+ 0, // src offset
+ ToCopy,
+ Mdl,
+ 0, // dest offset
+ &BytesCopied);
+ }
+ else
+ {
+ BytesCopied = 0;
+ }
+
+ // client's MDL is too short...
+ if (BytesCopied != ToCopy)
+ {
+ PUSH_LOCATION(0x42);
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Receive Buffer too short for Indicate buff BytesCopied %X, ToCopy %X\n",
+ BytesCopied, ToCopy));
+
+// ToCopy = BytesCopied;
+
+ // so the irp will be completed, below
+ ClientRcvLen = BytesCopied;
+ }
+
+ pLowerConn->BytesInIndicate -= (USHORT)BytesCopied;
+
+ // this case is only if the irp is full and should be returned
+ // now.
+ if (BytesCopied == ClientRcvLen)
+ {
+ PUSH_LOCATION(0x34);
+ // check if the indicate buffer is empty now. If not, then
+ // move the data forward to the start of the buffer.
+ //
+ if (pLowerConn->BytesInIndicate)
+ {
+ PUSH_LOCATION(0x43);
+ CopyToStartofIndicate(pLowerConn,BytesCopied);
+ }
+ //
+ // the irp is full so complete it
+ //
+ // the client MDL is full, so complete his irp
+ // CompletionRcv increments the number of bytes rcvd
+ // for this session pdu (pConnEle->BytesRcvd).
+ pIrp->IoStatus.Information = BytesCopied;
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+
+ // since we are completing it and TdiRcvHandler did not set the next
+ // one.
+ //
+ ASSERT(pIrp->CurrentLocation > 1);
+
+ IoSetNextIrpStackLocation(pIrp);
+
+ // we need to track how much of the client's MDL has filled
+ // up to know when to return it. CompletionRcv subtracts
+ // from this value as it receives bytes.
+ pConnEle->FreeBytesInMdl = ClientRcvLen;
+ pConnEle->CurrentRcvLen = ClientRcvLen;
+
+ //
+ // this will complete through CompletionRcv... and for that
+ // reason it will get any more data left in the transport. The
+ // Completion routine will set the correct state for the rcv when
+ // it processes this Irp ( to INDICATED, if needed).
+ //
+ if (pConnEle->ReceiveIndicated == 0)
+ {
+ PUSH_LOCATION(0x44);
+ ASSERT(pLowerConn->BytesInIndicate == 0);
+ pLowerConn->StateRcv = NORMAL;
+ pLowerConn->CurrentStateProc = Normal;
+
+ }
+ CTESpinFree(pLowerConn,OldIrq);
+
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ PUSH_LOCATION(0x35);
+ //
+ // clear the number of bytes in the indicate buffer since the client
+ // has taken more than the data left in the Indicate buffer
+ //
+ pLowerConn->BytesInIndicate = 0;
+
+ // decrement the client rcv len by the amount already put into the
+ // client Mdl
+ //
+ ClientRcvLen -= BytesCopied;
+ IF_DBG(NBT_DEBUG_RCV)
+ KdPrint(("Nbt: Pass Client Irp to Xport BytesinXport %X, ClientRcvLen %X\n",
+ pConnEle->BytesInXport,ClientRcvLen));
+ //
+ // Set the amount left inthe transport after this irp
+ // completes
+ if (pConnEle->BytesInXport < ClientRcvLen )
+ {
+ pConnEle->BytesInXport = 0;
+ }
+ else
+ {
+ PUSH_LOCATION(0x45);
+ pConnEle->BytesInXport -= ClientRcvLen;
+
+ }
+
+ // Adjust the number of bytes in the Mdl chain so far since the
+ // completion routine will only count the bytes filled in by the
+ // transport
+ pConnEle->BytesRcvd += BytesCopied;
+
+ // the client is going to take more data from the transport with
+ // this Irp. Set the new Rcv Length that accounts for the data just
+ // copied to the Irp.
+ //
+ pParams->ReceiveLength = ClientRcvLen;
+
+ IF_DBG(NBT_DEBUG_RCV)
+ KdPrint(("Nbt:ClientRcvLen = %X, LeftinXport= %X BytesCopied= %X %X\n",ClientRcvLen,
+ pConnEle->BytesInXport,BytesCopied,pLowerConn));
+
+ // set the state to this so we can undo the MDL footwork
+ // in completion rcv - since we have made a partial MDL and
+ // put that at the start of the chain.
+ //
+ pLowerConn->StateRcv = FILL_IRP;
+ pLowerConn->CurrentStateProc = FillIrp;
+
+ // Note that the Irp Mdl address changes below
+ // when MakePartialMdl is called so this line cannot
+ // be moved to the common code below!!
+ pLowerConn->pMdl = pIrp->MdlAddress;
+
+ // setup the next MDL so we can create a partial mdl correctly
+ // in TdiReceiveHandler
+ //
+ pConnEle->pNextMdl = pIrp->MdlAddress;
+
+ // Build a partial Mdl to represent the client's Mdl chain since
+ // we have copied data to it, and the transport must copy
+ // more data to it after that data.
+ //
+ // Force the system to map and lock the user buffer
+ MmGetSystemAddressForMdl(pIrp->MdlAddress);
+ MakePartialMdl(pConnEle,pIrp,BytesCopied);
+
+ // pass the Irp to the transport
+ //
+ //
+ IF_DBG(NBT_DEBUG_RCV)
+ KdPrint(("Nbt:Calling IoCallDriver\n"));
+ ASSERT(pIrp->CurrentLocation > 1);
+
+ }
+
+ }
+ else
+ {
+ PUSH_LOCATION(0x36);
+ IF_DBG(NBT_DEBUG_RCV)
+ KdPrint(("Nbt:Pass Irp To Xport Bytes in Xport %X, ClientRcvLen %X, RcvIndicated %X\n",
+ pConnEle->BytesInXport,ClientRcvLen,pConnEle->ReceiveIndicated));
+ //
+ // there are no bytes in the indicate buffer, so just pass the
+ // irp on down to the transport
+ //
+ //
+ // Decide the next state depending on whether the transport currently
+ // has enough data for this irp
+ //
+ if (pConnEle->BytesInXport < ClientRcvLen)
+ {
+ PUSH_LOCATION(0x37);
+ pConnEle->BytesInXport = 0;
+ //
+ // to get to here, the implication is that ReceiveIndicated
+ // equals zero too!! Since ReceiveInd cannot be more than
+ // BytesInXport, so we can change the state to fill irp without
+ // worrying about overwriting PartialRcv
+ //
+ pLowerConn->StateRcv = FILL_IRP;
+ pLowerConn->CurrentStateProc = FillIrp;
+ // setup the next MDL so we can create a partial mdl correctly
+ // in TdiReceiveHandler
+ //
+ pConnEle->pNextMdl = pIrp->MdlAddress;
+
+ }
+ else
+ {
+
+ PUSH_LOCATION(0x38);
+ pConnEle->BytesInXport -= ClientRcvLen;
+
+ // set the state to this so we know what to do in completion rcv
+ //
+ if (pConnEle->ReceiveIndicated == 0)
+ {
+ PUSH_LOCATION(0x39);
+ pLowerConn->StateRcv = NORMAL;
+ pLowerConn->CurrentStateProc = Normal;
+ }
+ }
+
+
+ //
+ // save the Irp so we can reconstruct things later
+ //
+ pLowerConn->pMdl = pIrp->MdlAddress;
+
+ }
+
+ // *** Common Code to passing irp to transport - when there is
+ // data in the indicate buffer and when there isn't
+
+ // keep track of data in MDL so we know when it is full
+ // and we need to return it to the user
+ //
+ pConnEle->FreeBytesInMdl = pParams->ReceiveLength;
+ // Force the system to map and lock the user buffer
+ MmGetSystemAddressForMdl(pIrp->MdlAddress);
+
+ //
+ // Null the Irp since we are passing it to the transport.
+ //
+ pConnEle->pIrpRcv = NULL;
+ CTESpinFree(pLowerConn,OldIrq);
+
+ CHECK_COMPLETION(pIrp);
+ status = IoCallDriver(IoGetRelatedDeviceObject(pLowerConn->pFileObject),pIrp);
+
+ }
+
+ return(status);
+ }
+
+ //
+ // session in wrong state so reject the buffer posting
+ //
+
+ PUSH_LOCATION(0x47);
+ //
+ // complete the irp, since there must have been some sort of error
+ // to get to here
+ //
+ NTIoComplete(pIrp,STATUS_REMOTE_DISCONNECT,0);
+
+ return(status);
+
+
+}
+//----------------------------------------------------------------------------
+ VOID
+NTCancelRcvDgram(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a listen Irp. It must release the
+ cancel spin lock before returning re: IoCancelIrp().
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ tCLIENTELE *pClientEle;
+ KIRQL OldIrq;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PIO_STACK_LOCATION pIrpSp;
+ tRCVELE *pRcvEle;
+
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got a Rcv Dgram Cancel !!! *****************\n"));
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ pClientEle = (tCLIENTELE *)pIrpSp->FileObject->FsContext;
+
+ if (pClientEle->Verify == NBT_VERIFY_CLIENT)
+ {
+ // now search the client's listen queue looking for this connection
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pHead = &pClientEle->RcvDgramHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pRcvEle = CONTAINING_RECORD(pEntry,tRCVELE,Linkage);
+ if (pRcvEle->pIrp == pIrp)
+ {
+ RemoveEntryList(pEntry);
+
+ // complete the irp
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ CTEMemFree((PVOID)pRcvEle);
+
+ return;
+
+ }
+ pEntry = pEntry->Flink;
+
+ }
+
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ return;
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTReceiveDatagram(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles receiving a datagram by passing the datagram rcv
+ buffer to the non-OS specific code.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION pIrpSp;
+ PTDI_REQUEST_KERNEL_RECEIVEDG pTdiRequest;
+ TDI_REQUEST Request;
+ ULONG ReceivedLength;
+ tCLIENTELE *pClientEle;
+
+ CTEPagedCode();
+
+ IF_DBG(NBT_DEBUG_RCV)
+ KdPrint(("Nbt: Got a Receive datagram that NBT was NOT \n"));
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ pClientEle = (tCLIENTELE *)pIrpSp->FileObject->FsContext;
+
+ // get the sending information out of the irp
+ pTdiRequest = (PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters;
+
+ Request.Handle.AddressHandle = pClientEle;
+
+ status = NbtReceiveDatagram(
+ &Request,
+ pTdiRequest->ReceiveDatagramInformation,
+ pTdiRequest->ReturnDatagramInformation,
+ pTdiRequest->ReceiveLength,
+ &ReceivedLength,
+ (PVOID)pIrp->MdlAddress, // user data
+ (tDEVICECONTEXT *)pDeviceContext,
+ pIrp);
+
+ if (status != STATUS_PENDING)
+ {
+
+ NTIoComplete(pIrp,status,ReceivedLength);
+
+ }
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTSend(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles sending session pdus across a connection. It is
+ all OS specific code.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL_SEND pTdiRequest;
+ PMDL pMdl;
+ PSINGLE_LIST_ENTRY pSingleListEntry;
+ tSESSIONHDR *pSessionHdr;
+ tCONNECTELE *pConnEle;
+ KIRQL OldIrq;
+ KIRQL OldIrq1;
+ PTDI_REQUEST_KERNEL_SEND pParams;
+ PFILE_OBJECT pFileObject;
+ tLOWERCONNECTION *pLowerConn;
+
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ // get the sending information out of the irp
+ pTdiRequest = (PTDI_REQUEST_KERNEL_SEND)&pIrpSp->Parameters;
+
+ pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
+ //ASSERT(pConnEle->Verify == NBT_VERIFY_CONNECTION);
+
+ if (pConnEle)
+ {
+ pLowerConn = pConnEle->pLowerConnId;
+ if (pLowerConn)
+ {
+ //
+ // make sure lowerconn stays valid until the irp is done
+ //
+ CTESpinLock(pLowerConn,OldIrq1);
+ pLowerConn->RefCount++;
+ CTESpinFree(pLowerConn,OldIrq1);
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:attempting send when LowerConn has been freed!\n"));
+
+ status = STATUS_INVALID_HANDLE;
+
+ // to save on indent levels use a goto here
+ goto ErrorExit;
+ }
+
+ CTESpinLock(pConnEle,OldIrq);
+
+ // check the state of the connection
+ if (pConnEle->state == NBT_SESSION_UP)
+ {
+ //
+ // send the data on downward to tcp
+ // allocate an MDL to allow us to put the session hdr in first and then
+ // put the users buffer on after that, chained to the session hdr MDL.
+ //
+ CTESpinLockAtDpc(&NbtConfig);
+
+ if (NbtConfig.SessionMdlFreeSingleList.Next)
+ {
+ pSingleListEntry = PopEntryList(&NbtConfig.SessionMdlFreeSingleList);
+ pMdl = CONTAINING_RECORD(pSingleListEntry,MDL,Next);
+
+ ASSERT ( MmGetMdlByteCount ( pMdl ) == sizeof ( tSESSIONHDR ) );
+
+ }
+ else
+ {
+ NbtGetMdl(&pMdl,eNBT_FREE_SESSION_MDLS);
+
+ if (!pMdl)
+ {
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:Unable to get an MDL for a session send!\n"));
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ CTESpinFreeAtDpc(&NbtConfig);
+ CTESpinFree(pConnEle,OldIrq);
+
+ // to save on indent levels use a goto here
+ goto ErrorExit;
+ }
+
+ }
+
+ CTESpinFreeAtDpc(&NbtConfig);
+
+ // get the session hdr address out of the MDL
+ pSessionHdr = (tSESSIONHDR *)MmGetMdlVirtualAddress(pMdl);
+
+ // the type of PDU is always a session message, since the session
+ // request is sent when the client issues a "connect" rather than a send
+ //
+ pSessionHdr->UlongLength = htonl(pTdiRequest->SendLength);
+
+ // get the device object and file object for the TCP transport underneath
+ // link the user buffer on the end of the session header Mdl on the Irp
+ //
+ pMdl->Next = pIrp->MdlAddress;
+ pIrp->MdlAddress = pMdl;
+
+ pIrpSp = IoGetNextIrpStackLocation(pIrp);
+
+ pParams = (PTDI_REQUEST_KERNEL_SEND)&pIrpSp->Parameters;
+ pParams->SendFlags = pTdiRequest->SendFlags;
+ pParams->SendLength = pTdiRequest->SendLength + sizeof(tSESSIONHDR);
+
+
+ pIrpSp->CompletionRoutine = SendCompletion;
+ pIrpSp->Context = (PVOID)pLowerConn;
+ pIrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
+
+ pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ pIrpSp->MinorFunction = TDI_SEND;
+
+ pFileObject = pLowerConn->pFileObject;
+ pLowerConn->BytesSent += pParams->SendLength;
+
+ pIrpSp->FileObject = pFileObject;
+ pIrpSp->DeviceObject = IoGetRelatedDeviceObject(pFileObject);
+
+
+ CTESpinFree(pConnEle,OldIrq);
+
+ CHECK_COMPLETION(pIrp);
+ status = IoCallDriver(IoGetRelatedDeviceObject(pFileObject),pIrp);
+
+ return(status);
+
+ }//correct state
+ else
+ {
+ CTESpinFree(pConnEle,OldIrq);
+ //
+ // Release pLowerConn->RefCount, grabbed above.
+ //
+ CTESpinLock(pLowerConn,OldIrq1);
+ pLowerConn->RefCount--;
+ CTESpinFree(pLowerConn,OldIrq1);
+
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:Invalid state for connection on an attempted send, %X\n",
+ pConnEle));
+ status = STATUS_INVALID_HANDLE;
+ }
+ }
+ else // pConnEle
+ {
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:attempting send with NULL Connection element!\n"));
+ status = STATUS_INVALID_HANDLE;
+ }
+
+
+ErrorExit:
+
+ //
+ // Reset the Irp pending flag
+ //
+ pIrpSp->Control &= ~SL_PENDING_RETURNED;
+ //
+ // complete the irp, since there must have been some sort of error
+ // to get to here
+ //
+ NTIoComplete(pIrp,status,0);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+SendCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion event when the send completes with
+ the underlying transport. It must put the session hdr buffer back in
+ the correct free list and free the active q entry and put it back on
+ its free list.
+
+Arguments:
+
+ DeviceObject - unused.
+
+ Irp - Supplies Irp that the transport has finished processing.
+
+ Context - Supplies the pConnectEle - the connection data structure
+
+Return Value:
+
+ The final status from the operation (success or an exception).
+
+--*/
+{
+ PMDL pMdl;
+ tLOWERCONNECTION *pLowerConn;
+
+ //
+ // Do some checking to keep the Io system happy - propagate the pending
+ // bit up the irp stack frame.... if it was set by the driver below then
+ // it must be set by me
+ //
+ if (Irp->PendingReturned)
+ {
+ IoMarkIrpPending(Irp);
+ }
+
+ // put the MDL we back on its free list and put the clients mdl back on the Irp
+ // as it was before the send
+ pMdl = Irp->MdlAddress;
+ Irp->MdlAddress = pMdl->Next;
+
+ ASSERT ( MmGetMdlByteCount ( pMdl ) == sizeof ( tSESSIONHDR ) );
+
+#if DBG
+ IF_DBG(NBT_DEBUG_SEND)
+ {
+ PMDL pMdl1;
+ ULONG ulen1,ulen2,ulen3;
+ UCHAR uc;
+ tSESSIONHDR *pSessionHdr;
+ PSINGLE_LIST_ENTRY pSingleListEntry;
+ KIRQL OldIrq;
+
+ pSessionHdr = (tSESSIONHDR *)MmGetMdlVirtualAddress(pMdl);
+ ulen1 = htonl ( pSessionHdr->UlongLength );
+
+ for ( ulen2 = 0 , pMdl1 = pMdl ; ( pMdl1 = pMdl1->Next ) != NULL ; ) {
+ ulen3 = MmGetMdlByteCount ( pMdl1 );
+ ASSERT ( ulen3 > 0 );
+ uc = ( ( UCHAR * ) MmGetMdlVirtualAddress ( pMdl1 ) ) [ ulen3 - 1 ];
+ ulen2 += ulen3;
+ }
+
+ ASSERT ( ulen2 == ulen1 );
+
+ CTESpinLock(&NbtConfig,OldIrq);
+ for ( pSingleListEntry = &NbtConfig.SessionMdlFreeSingleList ;
+ ( pSingleListEntry = pSingleListEntry->Next ) != NULL ;
+ )
+ {
+ pMdl1 = CONTAINING_RECORD(pSingleListEntry,MDL,Next);
+ ASSERT ( pMdl1 != pMdl );
+ }
+ CTESpinFree(&NbtConfig,OldIrq);
+ }
+#endif // DBG
+
+ ExInterlockedPushEntryList(&NbtConfig.SessionMdlFreeSingleList,
+ (PSINGLE_LIST_ENTRY)pMdl,
+ &NbtConfig.SpinLock);
+
+ // fill in the sent size so that it substracts off the session header size
+ //
+ if (Irp->IoStatus.Information > sizeof(tSESSIONHDR))
+ {
+
+ Irp->IoStatus.Information -= sizeof(tSESSIONHDR);
+ }
+ else
+ {
+ // nothing was sent
+ Irp->IoStatus.Information = 0;
+ IF_DBG(NBT_DEBUG_SEND)
+ KdPrint(("Nbt:Zero Send Length for a session send!\n"));
+ }
+
+ //
+ // we incremented this before the send: deref it now
+ //
+ pLowerConn = (tLOWERCONNECTION *)Context;
+#if DBG
+ if (!pLowerConn || pLowerConn->Verify != NBT_VERIFY_LOWERCONN)
+ {
+ ASSERTMSG("Nbt: LowerConn is not valid!\n",0);
+ }
+#endif
+ NbtDereferenceLowerConnection(pLowerConn);
+
+ return(STATUS_SUCCESS);
+
+ UNREFERENCED_PARAMETER( DeviceObject );
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTSendDatagram(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles sending a datagram down to the transport.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS status;
+ LONG lSentLength;
+ TDI_REQUEST Request;
+ PTDI_REQUEST_KERNEL_SENDDG pTdiRequest;
+ tCLIENTELE *pClientEle;
+
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ pClientEle = (tCLIENTELE *)pIrpSp->FileObject->FsContext;
+
+ CTEVerifyHandle(pClientEle,NBT_VERIFY_CLIENT,tCLIENTELE,&status);
+
+ // get the sending information out of the irp
+ pTdiRequest = (PTDI_REQUEST_KERNEL_SENDDG)&pIrpSp->Parameters;
+ Request.Handle.AddressHandle = pClientEle;
+
+ lSentLength = 0;
+ status = NbtSendDatagram(
+ &Request,
+ pTdiRequest->SendDatagramInformation,
+ pTdiRequest->SendLength,
+ &lSentLength,
+ (PVOID)pIrp->MdlAddress, // user data
+ (tDEVICECONTEXT *)pDeviceContext,
+ pIrp);
+
+
+ //
+ // either Success or an Error
+ // so complete the irp - PENDING is never returned!!
+ //
+ NTIoComplete(pIrp,status,lSentLength);
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTSetInformation(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles sets up event handlers that the client passes in.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ // *TODO*
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:************ Got a Set Information that was NOT expected *******\n"));
+ return(STATUS_SUCCESS);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTQueueToWorkerThread(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN PVOID pClientContext,
+ IN PVOID ClientCompletion,
+ IN PVOID CallBackRoutine,
+ IN PVOID pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine simply queues a request on an excutive worker thread
+ for later execution. Scanning the LmHosts file must be down this way.
+
+Arguments:
+ pTracker - the tracker block for context
+ CallbackRoutine - the routine for the Workerthread to call
+ pDeviceContext - the device context which is this delayed event
+ pertains to. This could be NULL (meaning it's an event
+ pertaining to not any specific device context)
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status = STATUS_UNSUCCESSFUL ;
+ NBT_WORK_ITEM_CONTEXT *pContext;
+
+ pContext = (NBT_WORK_ITEM_CONTEXT *)NbtAllocMem(sizeof(NBT_WORK_ITEM_CONTEXT),NBT_TAG('e'));
+ if (pContext)
+ {
+ pContext->pTracker = pTracker;
+ pContext->pClientContext = pClientContext;
+ pContext->ClientCompletion = ClientCompletion;
+
+ ExInitializeWorkItem(&pContext->Item,CallBackRoutine,pContext);
+ ExQueueWorkItem(&pContext->Item,DelayedWorkQueue);
+ status = STATUS_SUCCESS;
+ }
+
+ return(status);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+SecurityDelete(
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles deleting a security context at non-dpc level.
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ PSECURITY_CLIENT_CONTEXT pClientSecurity;
+
+ pClientSecurity = (PSECURITY_CLIENT_CONTEXT)((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
+ SeDeleteClientSecurity(pClientSecurity);
+ CTEMemFree(pContext);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NTSendSession(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN PVOID pCompletion)
+
+/*++
+Routine Description:
+
+ This Routine handles seting up a DPC to send a session pdu so that the stack
+ does not get wound up in multiple sends for the keep alive timeout case.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+{
+ PKDPC pDpc;
+
+ pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('f'));
+ if (!pDpc)
+ {
+ return;
+ }
+ KeInitializeDpc(pDpc,
+ DpcSendSession,
+ (PVOID)pTracker);
+
+ KeInsertQueueDpc(pDpc,(PVOID)pLowerConn,pCompletion);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+DpcSendSession(
+ IN PKDPC pDpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+/*++
+
+Routine Description:
+
+ This routine simply calls TcpSendSession from a Dpc started in
+ in NTSendSession (above).
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTEMemFree((PVOID)pDpc);
+
+
+ TcpSendSession((tDGRAM_SEND_TRACKING *)Context,
+ (tLOWERCONNECTION *)SystemArgument1,
+ (PVOID)SystemArgument2);
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTSetEventHandler(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS status;
+ tCLIENTELE *pClientEle;
+ PTDI_REQUEST_KERNEL_SET_EVENT pKeSetEvent;
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pClientEle = pIrpSp->FileObject->FsContext;
+ pKeSetEvent = (PTDI_REQUEST_KERNEL_SET_EVENT)&pIrpSp->Parameters;
+
+ // call the not NT specific routine to setup the event handler in the
+ // nbt data structures
+ status = NbtSetEventHandler(
+ pClientEle,
+ pKeSetEvent->EventType,
+ pKeSetEvent->EventHandler,
+ pKeSetEvent->EventContext);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+
+VOID
+NTIoComplete(
+ IN PIRP pIrp,
+ IN NTSTATUS Status,
+ IN ULONG SentLength)
+
+/*++
+Routine Description:
+
+ This Routine handles calling the NT I/O system to complete an I/O.
+
+Arguments:
+
+ status - a completion status for the Irp
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ KIRQL OldIrq;
+
+#if DBG
+ if (!NT_SUCCESS(Status))
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt: NTIoComplete error return status = %X\n",Status));
+// ASSERTMSG("Nbt: Error Ret Code In IoComplete",0);
+ }
+#endif
+
+ pIrp->IoStatus.Status = Status;
+
+ // use -1 as a flag to mean do not adjust the sent length since it is
+ // already set
+ if (SentLength != -1)
+ {
+ pIrp->IoStatus.Information = SentLength;
+ }
+
+#if DBG
+ if ( (Status != STATUS_SUCCESS) &&
+ (Status != STATUS_PENDING) &&
+ (Status != STATUS_INVALID_DEVICE_REQUEST) &&
+ (Status != STATUS_INVALID_PARAMETER) &&
+ (Status != STATUS_IO_TIMEOUT) &&
+ (Status != STATUS_BUFFER_OVERFLOW) &&
+ (Status != STATUS_BUFFER_TOO_SMALL) &&
+ (Status != STATUS_INVALID_HANDLE) &&
+ (Status != STATUS_INSUFFICIENT_RESOURCES) &&
+ (Status != STATUS_CANCELLED) &&
+ (Status != STATUS_DUPLICATE_NAME) &&
+ (Status != STATUS_TOO_MANY_NAMES) &&
+ (Status != STATUS_TOO_MANY_SESSIONS) &&
+ (Status != STATUS_REMOTE_NOT_LISTENING) &&
+ (Status != STATUS_BAD_NETWORK_PATH) &&
+ (Status != STATUS_HOST_UNREACHABLE) &&
+ (Status != STATUS_CONNECTION_REFUSED) &&
+ (Status != STATUS_WORKING_SET_QUOTA) &&
+ (Status != STATUS_REMOTE_DISCONNECT) &&
+ (Status != STATUS_LOCAL_DISCONNECT) &&
+ (Status != STATUS_LINK_FAILED) &&
+ (Status != STATUS_SHARING_VIOLATION) &&
+ (Status != STATUS_UNSUCCESSFUL) &&
+ (Status != STATUS_ACCESS_VIOLATION) &&
+ (Status != STATUS_NONEXISTENT_EA_ENTRY) )
+ {
+ KdPrint(("Nbt: returning unusual status = %X\n",Status));
+ }
+#endif
+
+ // set the Irps cancel routine to null or the system may bugcheck
+ // with a bug code of CANCEL_STATE_IN_COMPLETED_IRP
+ //
+ // refer to IoCancelIrp() ..\ntos\io\iosubs.c
+ //
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine(pIrp,NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+}
+//----------------------------------------------------------------------------
+
+NTSTATUS
+NTGetIrpIfNotCancelled(
+ IN PIRP pIrp,
+ IN PIRP *ppIrpInStruct
+ )
+/*++
+Routine Description:
+
+ This Routine gets the IOCancelSpinLock to coordinate with cancelling
+ irps It then returns STATUS_SUCCESS. It also nulls the irp in the structure
+ pointed to by the second parameter - so that the irp cancel routine
+ will not also be called.
+
+Arguments:
+
+ status - a completion status for the Irp
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ KIRQL OldIrq;
+ NTSTATUS status;
+
+ IoAcquireCancelSpinLock(&OldIrq);
+
+ // this nulls the irp in the datastructure - i.e. pConnEle->pIrp = NULL
+ *ppIrpInStruct = NULL;
+
+ if (!pIrp->Cancel)
+ {
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+ IoSetCancelRoutine(pIrp,NULL);
+
+ IoReleaseCancelSpinLock(OldIrq);
+
+ return(status);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTCheckSetCancelRoutine(
+ IN PIRP pIrp,
+ IN PVOID CancelRoutine,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+
+/*++
+Routine Description:
+
+ This Routine sets the cancel routine for an Irp.
+
+Arguments:
+
+ status - a completion status for the Irp
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+
+ //
+ // Check if the irp was cancelled yet and if not, then set the
+ // irp cancel routine.
+ //
+ IoAcquireCancelSpinLock(&pIrp->CancelIrql);
+ if (pIrp->Cancel)
+ {
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ status = STATUS_CANCELLED;
+
+ }
+ else
+ {
+ // setup the cancel routine
+ IoMarkIrpPending(pIrp);
+ IoSetCancelRoutine(pIrp,CancelRoutine);
+ status = STATUS_SUCCESS;
+ }
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ return(status);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTSetCancelRoutine(
+ IN PIRP pIrp,
+ IN PVOID CancelRoutine,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+
+/*++
+Routine Description:
+
+ This Routine sets the cancel routine for an Irp.
+
+Arguments:
+
+ status - a completion status for the Irp
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+
+ //
+ // Check if the irp was cancelled yet and if not, then set the
+ // irp cancel routine.
+ //
+ IoAcquireCancelSpinLock(&pIrp->CancelIrql);
+ if (pIrp->Cancel)
+ {
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ status = STATUS_CANCELLED;
+
+ //
+ // Note the cancel spin lock is released by the Cancel routine
+ //
+
+ (*(PDRIVER_CANCEL)CancelRoutine)((PDEVICE_OBJECT)pDeviceContext,pIrp);
+
+ }
+ else
+ {
+ // setup the cancel routine and mark the irp pending
+ //
+ IoMarkIrpPending(pIrp);
+ IoSetCancelRoutine(pIrp,CancelRoutine);
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ status = STATUS_SUCCESS;
+ }
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NTClearContextCancel(
+ IN NBT_WORK_ITEM_CONTEXT *pContext
+ )
+/*++
+Routine Description:
+
+ This Routine sets the cancel routine for
+ ((tDGRAM_SEND_TRACKING *)(pContext->pClientContext))->pClientIrp
+ to NULL.
+
+ NbtConfig.JointLock should be held when this routine is called.
+
+Arguments:
+
+ status - a completion status for the Irp
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+{
+ NTSTATUS status;
+ status = NTCancelCancelRoutine( ((tDGRAM_SEND_TRACKING *)(pContext->pClientContext))->pClientIrp );
+ ASSERT ( status != STATUS_CANCELLED );
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTCancelCancelRoutine(
+ IN PIRP pIrp
+ )
+
+/*++
+Routine Description:
+
+ This Routine sets the cancel routine for an Irp to NULL
+
+Arguments:
+
+ status - a completion status for the Irp
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if ( pIrp )
+ {
+ //
+ // Check if the irp was cancelled yet and if not, then set the
+ // irp cancel routine.
+ //
+ IoAcquireCancelSpinLock(&pIrp->CancelIrql);
+
+ if (pIrp->Cancel)
+ {
+ status = STATUS_CANCELLED;
+ }
+ IoSetCancelRoutine(pIrp,NULL);
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ }
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+FindNameCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a FindName Irp - which has
+ been passed down by a client (e.g. ping). Typically, when ping succeeds
+ on another adapter, it will issue this cancel.
+ On receiving the cancel, we stop any timer that is running in connection
+ with name query and then complete the irp with status_cancelled.
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ PIO_STACK_LOCATION pIrpSp;
+
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got a FindName Irp Cancel !!! *****************\n"));
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pTracker = pIrpSp->Parameters.Others.Argument4;
+
+ //
+ // We want to ensure that the tracker supplied by FsContext
+ // is the right Tracker for this Irp
+ //
+ if (pTracker && (pIrp == pTracker->pClientIrp))
+ {
+ //
+ // if pClientIrp still valid, completion routine hasn't run yet: go ahead
+ // and complete the irp here
+ //
+ pIrpSp->Parameters.Others.Argument4 = NULL;
+ pTracker->pClientIrp = NULL;
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ NTIoComplete(pIrp,STATUS_CANCELLED,(ULONG)-1);
+
+ } else
+ {
+ //
+ // the completion routine has run.
+ //
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ }
+
+ return;
+}
+
diff --git a/private/ntos/nbt/nt/ntpnp.c b/private/ntos/nbt/nt/ntpnp.c
new file mode 100644
index 000000000..20dbc90b5
--- /dev/null
+++ b/private/ntos/nbt/nt/ntpnp.c
@@ -0,0 +1,682 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ NTPNP.c
+
+Abstract:
+
+ This module implements the DRIVER_INITIALIZATION routine for the
+ NBT Transport and other routines that are specific to the NT implementation
+ of a driver.
+
+Author:
+
+ Earle R. Horton (earleh) 08-Nov-1995
+
+Revision History:
+
+--*/
+
+
+#include "nbtprocs.h"
+
+#ifdef _PNP_POWER
+
+NTSTATUS
+NbtNtPNPInit(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Some general driver initialization that we postpone until we have
+ an actual IP address to which to bind.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NTSTATUS - The function value is the final status from the initialization
+ operations.
+
+--*/
+
+{
+ NTSTATUS status;
+
+ // start some timers
+ status = InitTimersNotOs();
+
+ if (!NT_SUCCESS(status))
+ {
+ NbtLogEvent(EVENT_NBT_TIMERS,status);
+ KdPrint(("NBT:Failed to Initialize the Timers!,status = %X\n",
+ status));
+ StopInitTimers();
+ return(status);
+ }
+
+}
+
+VOID
+NbtFailedNtPNPInit(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Undo some general driver initialization that we postpone until we have
+ an actual IP address to which to bind. Called after NbtAddressAdd()
+ failed to add the desired address, and no other addresses had been
+ added previously.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ NTSTATUS - The function value is the final status from the initialization
+ operations.
+
+--*/
+
+{
+ StopInitTimers();
+}
+
+NTSTATUS
+NbtAddressAdd(
+ ULONG IpAddr,
+ PUNICODE_STRING pucBindString,
+ PUNICODE_STRING pucExportString,
+ PULONG Inst
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ NTSTATUS dontcarestatus;
+ tDEVICES *pBindDevices = NULL;
+ tDEVICES *pExportDevices = NULL;
+ tDEVICES BindDevices;
+ tDEVICES ExportDevices;
+ tADDRARRAY *pAddrArray = NULL;
+
+ ULONG ulIpAddress;
+ ULONG ulSubnetMask;
+
+ int i;
+
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ tDEVICECONTEXT *pDeviceContext = NULL;
+
+ BOOLEAN Attached;
+
+ if (NbtConfig.uDevicesStarted == 0)
+ {
+ status = NbtNtPNPInit();
+ if ( status != STATUS_SUCCESS ) {
+ KdPrint(("NetBT!NbtAddressAdd: Global driver initialization failed,\nfailing to add address %d%d%d%d.\n",IpAddr&0xFF,(IpAddr>>8)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>24)&0xFF));
+ return status;
+ }
+ }
+
+ if (IpAddr) {
+ CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
+
+ //
+ // Find the bind and export devices to use from the device
+ // described in the registry that uses this address.
+ //
+ status = NbtReadRegistry(
+ &NbtConfig.pRegistry,
+ NULL, // Null Driver Object
+ &NbtConfig,
+ &pBindDevices,
+ &pExportDevices,
+ &pAddrArray);
+
+ CTEExReleaseResource(&NbtConfig.Resource);
+ } else {
+ status = STATUS_SUCCESS;
+ ASSERT(pucBindString);
+ ASSERT(pucExportString);
+
+ //
+ // Init the bind/export structs
+ //
+ BindDevices.RegistrySpace = pucBindString->Buffer;
+ BindDevices.Names[0] = *pucBindString;
+
+ ExportDevices.RegistrySpace = pucExportString->Buffer;
+ ExportDevices.Names[0] = *pucExportString;
+
+ pBindDevices = &BindDevices;
+ pExportDevices = &ExportDevices;
+ }
+
+ if (
+ ( status == STATUS_SUCCESS )
+ && ( pBindDevices != NULL )
+ )
+ {
+
+ for (i=0; i<pNbtGlobConfig->uNumDevices; i++ )
+ {
+ BOOLEAN fStatic = TRUE;
+
+ //
+ // Fetch a static IP address from the registry.
+ //
+ status = GetIPFromRegistry(
+ &NbtConfig.pRegistry,
+ &pBindDevices->Names[i],
+ &ulIpAddress,
+ &ulSubnetMask,
+ FALSE);
+ if ( status == STATUS_INVALID_ADDRESS )
+ {
+ fStatic = FALSE;
+
+ //
+ // This one doesn't have a valid static address. Try DHCP.
+ //
+ status = GetIPFromRegistry(
+ &NbtConfig.pRegistry,
+ &pBindDevices->Names[i],
+ &ulIpAddress,
+ &ulSubnetMask,
+ TRUE);
+ }
+
+ if (((status == STATUS_SUCCESS) && ( ulIpAddress == IpAddr )) ||
+ !IpAddr)
+ {
+ pDeviceContext = NbtFindBindName ( &pBindDevices->Names[i] );
+
+ if ( pDeviceContext != NULL )
+ {
+ //
+ // Device already exists. Do something sensible with it.
+ //
+
+ //
+ // For static addresses, open the addresses with the transports; add the permanent name
+ //
+ if (fStatic) {
+
+#ifdef _PNP_POWER
+ //
+ // these are passed into here in the reverse byte order, wrt to the IOCTL
+ // from DHCP.
+ //
+ (VOID)NbtNewDhcpAddress(pDeviceContext,htonl(ulIpAddress),htonl(ulSubnetMask));
+#endif // NOTYET_PNP
+ //
+ // Add the "permanent" name to the local name table. This is the IP
+ // address of the node padded out to 16 bytes with zeros.
+ //
+ status = NbtAddPermanentName(pDeviceContext);
+ }
+
+ //
+ // If the device was not registered with TDI, do so now.
+ //
+
+ //
+ // By-pass the TDI PnP mechanism for logical interfaces
+ //
+ if (IpAddr) {
+ if (pDeviceContext->RegistrationHandle == NULL) {
+ // pDeviceContext->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
+
+ status = TdiRegisterDeviceObject(
+ &pExportDevices->Names[i],
+ &pDeviceContext->RegistrationHandle);
+
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("Couldn't register device object\n"));
+ }
+ }
+ } else {
+ pDeviceContext->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
+ }
+ }
+ else
+ {
+ BOOLEAN Attached = FALSE;
+
+ //
+ // Attach to the system process so that all handles are created in the
+ // proper context.
+ //
+ CTEAttachFsp(&Attached);
+
+ status = NbtCreateDeviceObject(
+ NbtConfig.DriverObject,
+ &NbtConfig,
+ &pBindDevices->Names[i],
+ &pExportDevices->Names[i],
+ &pAddrArray[i],
+ &NbtConfig.pRegistry,
+
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ (BOOLEAN)(IpAddr == 0),
+#endif
+ &pDeviceContext);
+
+ //
+ // allow not having an address to succeed - DHCP will
+ // provide an address later
+ //
+ if (pDeviceContext != NULL)
+ {
+ if ((status == STATUS_INVALID_ADDRESS) ||
+ (!IpAddr && (status == STATUS_UNSUCCESSFUL)))
+ {
+ //
+ // set to null so we know not to allow connections or dgram
+ // sends on this adapter
+ //
+ pDeviceContext->IpAddress = 0;
+
+ status = STATUS_SUCCESS;
+
+ }
+ //
+ // Get an Irp for the out of resource queue (used to disconnect sessions
+ // when really low on memory)
+ //
+ if ( NT_SUCCESS(status) && !NbtConfig.OutOfRsrc.pIrp )
+ {
+ pEntry = NbtConfig.DeviceContexts.Flink;
+
+ ASSERT (pDeviceContext == CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage));
+
+ NbtConfig.OutOfRsrc.pIrp = NTAllocateNbtIrp(&pDeviceContext->DeviceObject);
+
+ if (!NbtConfig.OutOfRsrc.pIrp)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ //
+ // allocate a dpc structure and keep it: we might need if we hit an
+ // out-of-resource condition
+ //
+ NbtConfig.OutOfRsrc.pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('a'));
+ if (!NbtConfig.OutOfRsrc.pDpc)
+ {
+ IoFreeIrp(NbtConfig.OutOfRsrc.pIrp);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ }
+ if (NT_SUCCESS(status))
+ {
+ NbtConfig.uDevicesStarted++;
+ pDeviceContext->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
+
+ //
+ // By-pass the TDI PnP mechanism for logical interfaces
+ //
+ if (IpAddr) {
+ status = TdiRegisterDeviceObject(
+ &pExportDevices->Names[i],
+ &pDeviceContext->RegistrationHandle);
+ }
+ }
+ //
+ // Clean up code if device created but we could not use it
+ // for some reason.
+ //
+ if (!NT_SUCCESS(status))
+ {
+
+ pDeviceContext->RegistrationHandle = NULL;
+
+ KdPrint((" Create Device Object Failed with status= %X, num devices = %X\n",status,
+ NbtConfig.uNumDevices));
+
+ NbtLogEvent(EVENT_NBT_CREATE_DEVICE,status);
+ //
+ // this device will not be started so decrement the count of started
+ // ones.
+ //
+ NbtConfig.AdapterCount--;
+
+ pHead = &NbtConfig.DeviceContexts;
+ pEntry = RemoveTailList(pHead);
+
+ ASSERT (pDeviceContext == CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage));
+
+ if (pDeviceContext->hNameServer)
+ {
+ ObDereferenceObject(pDeviceContext->pNameServerFileObject);
+ dontcarestatus = NTZwCloseFile(pDeviceContext->hNameServer);
+ KdPrint(("Close NameSrv File status = %X\n",dontcarestatus));
+ }
+ if (pDeviceContext->hDgram)
+ {
+ ObDereferenceObject(pDeviceContext->pDgramFileObject);
+ dontcarestatus = NTZwCloseFile(pDeviceContext->hDgram);
+ KdPrint(("Close Dgram File status = %X\n",dontcarestatus));
+ }
+ if (pDeviceContext->hSession)
+ {
+ ObDereferenceObject(pDeviceContext->pSessionFileObject);
+ dontcarestatus = NTZwCloseFile(pDeviceContext->hSession);
+ KdPrint(("Close Session File status = %X\n",dontcarestatus));
+ }
+ if (pDeviceContext->hControl)
+ {
+ ObDereferenceObject(pDeviceContext->pControlFileObject);
+ dontcarestatus = NTZwCloseFile(pDeviceContext->hControl);
+ KdPrint(("Close Control File status = %X\n",dontcarestatus));
+ }
+
+ IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext);
+ }
+ }
+
+ CTEDetachFsp(Attached);
+ }
+ break;
+ } // ( (status == STATUS_SUCCESS) && ( ulIpAddress == IpAddr ) )
+ }
+ }
+
+
+ if (NbtConfig.uDevicesStarted == 0)
+ {
+ NbtFailedNtPNPInit();
+ }
+
+ if (IpAddr) {
+ if (pBindDevices)
+ {
+ CTEMemFree((PVOID)pBindDevices->RegistrySpace);
+ CTEMemFree((PVOID)pBindDevices);
+ }
+ if (pExportDevices)
+ {
+ CTEMemFree((PVOID)pExportDevices->RegistrySpace);
+ CTEMemFree((PVOID)pExportDevices);
+ }
+ if (pAddrArray)
+ {
+ CTEMemFree((PVOID)pAddrArray);
+ }
+ } else {
+ if (pDeviceContext) {
+ *Inst = pDeviceContext->InstanceNumber;
+#if DBG
+ pDeviceContext->IsDynamic = TRUE;
+#endif
+ }
+ }
+
+ return status;
+}
+
+tDEVICECONTEXT *
+NbtFindIPAddress(
+ ULONG IpAddr
+ )
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ tDEVICECONTEXT *pDeviceContext;
+
+ pHead = &NbtConfig.DeviceContexts;
+ pEntry = pHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+
+ if ( pDeviceContext->IpAddress == IpAddr )
+ {
+ return pDeviceContext;
+ }
+ }
+ return (tDEVICECONTEXT *)NULL;
+}
+
+tDEVICECONTEXT *
+NbtFindBindName(
+ PUNICODE_STRING pucBindName
+ )
+{
+
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ tDEVICECONTEXT *pDeviceContext;
+
+ pHead = &NbtConfig.DeviceContexts;
+ pEntry = pHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+
+ if ( RtlCompareUnicodeString(
+ pucBindName,
+ &pDeviceContext->BindName,
+ FALSE )
+ == 0 )
+ {
+ return pDeviceContext;
+ }
+ }
+ return (tDEVICECONTEXT *)NULL;
+}
+
+VOID
+NbtAddressDelete(
+ ULONG IpAddr
+ )
+{
+ tDEVICECONTEXT *pDeviceContext;
+
+ if ( ( pDeviceContext = NbtFindIPAddress ( IpAddr ) ) != NULL )
+ {
+ (VOID)NbtNewDhcpAddress(pDeviceContext,0,0);
+ }
+}
+
+HANDLE AddressChangeHandle;
+
+#ifdef WATCHBIND
+HANDLE BindingHandle;
+#endif // WATCHBIND
+
+//* AddressArrival - Handle an IP address arriving
+//
+// Called by TDI when an address arrives.
+//
+// Input: Addr - IP address that's coming.
+//
+// Returns: Nothing.
+//
+VOID
+AddressArrival(PTA_ADDRESS Addr)
+{
+ ULONG IpAddr;
+ if (Addr->AddressType == TDI_ADDRESS_TYPE_IP){
+ IpAddr = ntohl(((PTDI_ADDRESS_IP)&Addr->Address[0])->in_addr);
+ IF_DBG(NBT_DEBUG_PNP_POWER){
+ KdPrint(("NetBT!AddressArrival: %d.%d.%d.%d\n",(IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF));
+ }
+ if (IpAddr)
+ {
+ (VOID)NbtAddressAdd(IpAddr, NULL, NULL, NULL);
+ }
+ }
+}
+
+//* AddressDeletion - Handle an IP address going away.
+//
+// Called by TDI when an address is deleted. If it's an address we
+// care about we'll clean up appropriately.
+//
+// Input: Addr - IP address that's going.
+//
+// Returns: Nothing.
+//
+VOID
+AddressDeletion(PTA_ADDRESS Addr)
+{
+ ULONG IpAddr;
+ if (Addr->AddressType == TDI_ADDRESS_TYPE_IP){
+ IpAddr = ntohl(((PTDI_ADDRESS_IP)&Addr->Address[0])->in_addr);
+ IF_DBG(NBT_DEBUG_PNP_POWER){
+ KdPrint(("NetBT!AddressDeletion: %d.%d.%d.%d\n",(IpAddr>>24)&0xFF,(IpAddr>>16)&0xFF,(IpAddr>>8)&0xFF,IpAddr&0xFF));
+ }
+ if (IpAddr)
+ {
+ NbtAddressDelete(IpAddr);
+ }
+ }
+}
+
+ NTSTATUS
+NbtAddNewInterface (
+ IN PIRP pIrp,
+ IN PVOID *pBuffer,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+ Creates a device context by coming up with a unique export string to name
+ the device.
+
+Arguments:
+
+Return Value:
+
+Notes:
+
+
+--*/
+{
+ ULONG nextIndex = InterlockedIncrement(&NbtConfig.InterfaceIndex);
+ WCHAR Suffix[16];
+ WCHAR Bind[60] = L"\\Device\\If";
+ WCHAR Export[60] = L"\\Device\\NetBt_If";
+ UNICODE_STRING ucSuffix;
+ UNICODE_STRING ucBindStr;
+ UNICODE_STRING ucExportStr;
+ NTSTATUS status;
+ ULONG OutSize;
+ ULONG Inst=0;
+ PNETBT_ADD_DEL_IF pAddDelIf = (PNETBT_ADD_DEL_IF)pBuffer;
+
+ //
+ // Validate output buffer size
+ //
+ if (Size < sizeof(NETBT_ADD_DEL_IF)) {
+ KdPrint(("NbtAddNewInterface: Output buffer too small for struct\n"));
+ return(STATUS_INVALID_PARAMETER);
+ }
+ //
+ // Create the bind/export strings as:
+ // Bind: \Device\IF<1> Export: \Device\NetBt_IF<1>
+ // where 1 is a unique interface index.
+ //
+ ucSuffix.Buffer = Suffix;
+ ucSuffix.Length = 0;
+ ucSuffix.MaximumLength = sizeof(Suffix);
+
+ RtlIntegerToUnicodeString(nextIndex, 10, &ucSuffix);
+
+ RtlInitUnicodeString(&ucBindStr, Bind);
+ ucBindStr.MaximumLength = sizeof(Bind);
+ RtlInitUnicodeString(&ucExportStr, Export);
+ ucExportStr.MaximumLength = sizeof(Export);
+
+ RtlAppendUnicodeStringToString(&ucBindStr, &ucSuffix);
+ RtlAppendUnicodeStringToString(&ucExportStr, &ucSuffix);
+
+ OutSize = FIELD_OFFSET (NETBT_ADD_DEL_IF, IfName[0]) +
+ ucExportStr.Length + sizeof(UNICODE_NULL);
+
+ if (Size < OutSize) {
+ KdPrint(("NbtAddNewInterface: Buffer too small for name\n"));
+ pAddDelIf->Length = ucExportStr.Length + sizeof(UNICODE_NULL);
+ pAddDelIf->Status = STATUS_BUFFER_TOO_SMALL;
+ pIrp->IoStatus.Information = sizeof(NETBT_ADD_DEL_IF);
+ return STATUS_SUCCESS;
+ }
+
+ KdPrint((
+ "Created: ucBindStr: %ws ucExportStr: %ws\n",
+ ucBindStr.Buffer,
+ ucExportStr.Buffer
+ ));
+
+ status = NbtAddressAdd(0, &ucBindStr, &ucExportStr, &Inst);
+
+ if (status == STATUS_SUCCESS) {
+ //
+ // Fill up the output buffer with the export name
+ //
+ RtlCopyMemory(
+ &pAddDelIf->IfName[0],
+ ucExportStr.Buffer,
+ ucExportStr.Length + sizeof(UNICODE_NULL)
+ );
+
+ pAddDelIf->InstanceNumber = Inst;
+ pAddDelIf->Length = ucExportStr.Length + sizeof(UNICODE_NULL);
+ pAddDelIf->Status = STATUS_SUCCESS;
+ pIrp->IoStatus.Information = OutSize;
+ }
+
+ return status;
+}
+
+#ifdef WATCHBIND
+
+//* BindHandler - Handle a new transport device object.
+//
+// Called by TDI when a new transport device object is created.
+//
+// Input: DeviceName - Name of the new device object.
+//
+// Returns: Nothing.
+//
+
+VOID
+BindHandler(IN PUNICODE_STRING DeviceName)
+{
+}
+
+//* UnbindHandler - Handle deletion of a transport device object.
+//
+// Called by TDI when a transport device object is deleted.
+//
+// Input: DeviceName - Name of the deleted device object.
+//
+// Returns: Nothing.
+//
+
+VOID
+UnbindHandler(IN PUNICODE_STRING DeviceName)
+{
+}
+
+#endif // WATCHBIND
+
+#endif // _PNP_POWER
diff --git a/private/ntos/nbt/nt/ntutil.c b/private/ntos/nbt/nt/ntutil.c
new file mode 100644
index 000000000..4a5f200b8
--- /dev/null
+++ b/private/ntos/nbt/nt/ntutil.c
@@ -0,0 +1,2103 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Ntutil.c
+
+Abstract:
+
+ This file contains a number of utility and support routines that are
+ NT specific.
+
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+#include "stdio.h"
+#include <ntddtcp.h>
+#undef uint // undef to avoid a warning where tdiinfo.h redefines it
+#include <tdiinfo.h>
+#include <ipinfo.h>
+
+NTSTATUS
+CreateControlObject(
+ tNBTCONFIG *pConfig);
+
+NTSTATUS
+IfNotAnyLowerConnections(
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+NTSTATUS
+NbtProcessDhcpRequest(
+ tDEVICECONTEXT *pDeviceContext);
+VOID
+GetExtendedAttributes(
+ tDEVICECONTEXT *pDeviceContext
+ );
+
+PSTRM_PROCESSOR_LOG LogAlloc ;
+PSTRM_PROCESSOR_LOG LogFree ;
+
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#ifdef _PNP_POWER
+#pragma CTEMakePageable(PAGE, NbtCreateDeviceObject)
+#else // _PNP_POWER
+#pragma CTEMakePageable(INIT, NbtCreateDeviceObject)
+#endif // _PNP_POWER
+#pragma CTEMakePageable(PAGE, CreateControlObject)
+#pragma CTEMakePageable(PAGE, NbtInitConnQ)
+#pragma CTEMakePageable(PAGE, NbtProcessDhcpRequest)
+#pragma CTEMakePageable(PAGE, NbtCreateAddressObjects)
+#pragma CTEMakePageable(PAGE, GetExtendedAttributes)
+#pragma CTEMakePageable(PAGE, ConvertToUlong)
+#pragma CTEMakePageable(PAGE, NbtInitMdlQ)
+#pragma CTEMakePageable(PAGE, NTZwCloseFile)
+#pragma CTEMakePageable(PAGE, NTReReadRegistry)
+#pragma CTEMakePageable(PAGE, SaveClientSecurity)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+ulong
+GetUnique32BitValue(
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a reasonably unique 32-bit number based on the system clock.
+ In NT, we take the current system time, convert it to milliseconds,
+ and return the low 32 bits.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A reasonably unique 32-bit value.
+
+--*/
+
+{
+ LARGE_INTEGER ntTime, tmpTime;
+
+ KeQuerySystemTime(&ntTime);
+
+ tmpTime = CTEConvert100nsToMilliseconds(ntTime);
+
+ return(tmpTime.LowPart);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtCreateDeviceObject(
+ PDRIVER_OBJECT DriverObject,
+ tNBTCONFIG *pConfig,
+ PUNICODE_STRING pucBindName,
+ PUNICODE_STRING pucExportName,
+ tADDRARRAY *pAddrs,
+ PUNICODE_STRING pucRegistryPath,
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ BOOLEAN fReuse,
+#endif
+ tDEVICECONTEXT **ppDeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a Driver Object from the device object passed
+ in and the name of the driver object passed in. After the Driver Object
+ has been created, clients can "Open" the driver by that name.
+
+Arguments:
+
+
+Return Value:
+
+ status - the outcome
+
+--*/
+
+{
+
+ NTSTATUS status;
+ PDEVICE_OBJECT DeviceObject = NULL;
+ tDEVICECONTEXT *pDeviceContext;
+ ULONG LinkOffset;
+ ULONG ulIpAddress;
+ ULONG ulSubnetMask;
+#ifdef _PNP_POWER
+ PUCHAR Buffer;
+#endif // _PNP_POWER
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ BOOLEAN fIsItReused=FALSE;
+#endif
+ CTELockHandle OldIrq1;
+
+ CTEPagedCode();
+
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ //
+ // If we can re-use some of the earlier devices, so be it....
+ // This will go away when base supports IoDeleteDevice properly.
+ //
+ if (fReuse) {
+ LIST_ENTRY *pEntry;
+
+ CTESpinLock(&NbtConfig, OldIrq1);
+ if (!IsListEmpty(&NbtConfig.FreeDevCtx)) {
+ pEntry = RemoveHeadList( &NbtConfig.FreeDevCtx);
+
+ DeviceObject = (PDEVICE_OBJECT) CONTAINING_RECORD( pEntry,
+ tDEVICECONTEXT,
+ FreeLinkage);
+
+ KdPrint(("Re-using device @ %lx, bind: %ws\n", DeviceObject, ((tDEVICECONTEXT *)DeviceObject)->BindName.Buffer));
+
+ //
+ // Re-use the name and update the value returned to the user - we shd decrement
+ // the global ptr too, but we might hit some other (valid) device the next time on.
+ //
+ pucBindName->MaximumLength = ((tDEVICECONTEXT *)DeviceObject)->BindName.MaximumLength;
+ RtlCopyUnicodeString(pucBindName, &((tDEVICECONTEXT *)DeviceObject)->BindName);
+
+ pucExportName->MaximumLength = ((tDEVICECONTEXT *)DeviceObject)->ExportName.MaximumLength;
+ RtlCopyUnicodeString(pucExportName, &((tDEVICECONTEXT *)DeviceObject)->ExportName);
+ CTEMemFree( pDeviceContext->ExportName.Buffer );
+
+ CTESpinFree(&NbtConfig, OldIrq1);
+
+ fIsItReused = TRUE;
+#ifdef _PNP_POWER
+ Buffer = NbtAllocMem(pucExportName->MaximumLength+pucBindName->MaximumLength,NBT_TAG('w'));
+
+ if ( Buffer == NULL )
+ {
+ return STATUS_INSUFFICIENT_RESOURCES ;
+ }
+#endif // _PNP_POWER
+ goto Reuse;
+ }
+
+ fIsItReused = FALSE;
+ CTESpinFree(&NbtConfig, OldIrq1);
+ }
+#endif
+
+#ifdef _PNP_POWER
+ Buffer = NbtAllocMem(pucExportName->MaximumLength+pucBindName->MaximumLength,NBT_TAG('w'));
+
+ if ( Buffer == NULL )
+ {
+ return STATUS_INSUFFICIENT_RESOURCES ;
+ }
+#endif // _PNP_POWER
+
+
+ status = IoCreateDevice(
+ DriverObject, // Driver Object
+ sizeof(tDEVICECONTEXT) - sizeof(DRIVER_OBJECT), //Device Extension
+ pucExportName, // Device Name
+ FILE_DEVICE_NBT, // Device type 0x32 for now...
+ 0, //Device Characteristics
+ FALSE, //Exclusive
+ &DeviceObject );
+
+ if (!NT_SUCCESS( status ))
+ {
+ KdPrint(("Failed to create the Export Device, status=%X\n",status));
+ *ppDeviceContext = NULL;
+#ifdef _PNP_POWER
+ CTEMemFree ( Buffer );
+#endif // _PNP_POWER
+ return status;
+ }
+
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+Reuse:
+#endif
+
+ *ppDeviceContext = pDeviceContext = (tDEVICECONTEXT *)DeviceObject;
+
+ //
+ // zero out the data structure, beyond the OS specific part
+ //
+ LinkOffset = (ULONG)(&((tDEVICECONTEXT *)0)->Linkage);
+ CTEZeroMemory(&pDeviceContext->Linkage,sizeof(tDEVICECONTEXT) - LinkOffset);
+
+#ifdef _PNP_POWER
+ pDeviceContext->ExportName.MaximumLength = pucExportName->MaximumLength;
+ pDeviceContext->ExportName.Buffer = (PWSTR)Buffer;
+
+ RtlCopyUnicodeString(&pDeviceContext->ExportName,pucExportName);
+
+ pDeviceContext->BindName.MaximumLength = pucBindName->MaximumLength;
+ pDeviceContext->BindName.Buffer = (PWSTR)(Buffer+pucExportName->MaximumLength);
+ RtlCopyUnicodeString(&pDeviceContext->BindName,pucBindName);
+#endif // _PNP_POWER
+
+ // initialize the pDeviceContext data structure. There is one of
+ // these data structured tied to each "device" that NBT exports
+ // to higher layers (i.e. one for each network adapter that it
+ // binds to.
+ // The initialization sets the forward link equal to the back link equal
+ // to the list head
+ InitializeListHead(&pDeviceContext->UpConnectionInUse);
+ InitializeListHead(&pDeviceContext->LowerConnection);
+ InitializeListHead(&pDeviceContext->LowerConnFreeHead);
+
+ // put a verifier value into the structure so that we can check that
+ // we are operating on the right data when the OS passes a device context
+ // to NBT
+ pDeviceContext->Verify = NBT_VERIFY_DEVCONTEXT;
+
+ // setup the spin lock);
+ CTEInitLock(&pDeviceContext->SpinLock);
+
+ pDeviceContext->LockNumber = DEVICE_LOCK;
+ //
+ // for a Bnode pAddrs is NULL
+ //
+ if (pAddrs)
+ {
+ pDeviceContext->lNameServerAddress = pAddrs->NameServerAddress;
+ pDeviceContext->lBackupServer = pAddrs->BackupServer;
+ //
+ // if the node type is set to Bnode by default then switch to Hnode if
+ // there are any WINS servers configured.
+ //
+ if ((NodeType & DEFAULT_NODE_TYPE) &&
+ (pAddrs->NameServerAddress || pAddrs->BackupServer))
+ {
+ NodeType = MSNODE | (NodeType & PROXY_NODE);
+ }
+ }
+
+ //
+ // We need to acquire this lock since we can have multiple devices
+ // being added simultaneously and hence we will need to have a unique
+ // Adapter Number for each device
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ // keep a bit mask around to keep track of this adapter number so we can
+ // quickly find if a given name is registered on a particular adapter,
+ // by a corresponding bit set in the tNAMEADDR - local hash table
+ // entry
+ //
+ pDeviceContext->AdapterNumber = (CTEULONGLONG)1 << NbtConfig.AdapterCount;
+ NbtConfig.AdapterCount++;
+
+ // add this new device context on to the List in the configuration
+ // data structure
+ InsertTailList(&pConfig->DeviceContexts,&pDeviceContext->Linkage);
+
+ if (NbtConfig.AdapterCount > 1)
+ {
+ NbtConfig.MultiHomed = TRUE;
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // increase the stack size of our device object, over that of the transport
+ // so that clients create Irps large enough
+ // to pass on to the transport below.
+ // In theory, we should just add 1 here, to account for out presence in the
+ // driver chain.
+
+ status = NbtTdiOpenControl(pDeviceContext);
+ if (NT_SUCCESS(status))
+ {
+ DeviceObject->StackSize = pDeviceContext->pControlDeviceObject->StackSize + 1;
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Nbt!NbtTdiOpenControl returned status=%X\n",status));
+ return(status);
+ }
+
+
+ //
+ // An instance number is assigned to each device so that the service which
+ // creates logical devices in Nbt can re-use these devices in case it fails
+ // to destroy them in a prev. instance.
+ //
+ pDeviceContext->InstanceNumber = GetUnique32BitValue();
+
+ //
+ // To create the address objects for this device we need an address for
+ // TCP port 139 (session services, UDP Port 138 (datagram services)
+ // and UDP Port 137 (name services). The IP addresses to use for these
+ // port number must be found by "groveling" the registry..i.e. looking
+ // under each adapter in the registry for a /parameters/tcpip section
+ // and then pulling the IP address out of that
+ //
+ status = GetIPFromRegistry(
+ pucRegistryPath,
+ pucBindName,
+ &ulIpAddress,
+ &ulSubnetMask,
+ FALSE);
+
+#ifdef _PNP_POWER
+#ifdef NOTYET_PNP
+ if ( status == STATUS_INVALID_ADDRESS )
+ {
+ //
+ // This one doesn't have a valid static address. Try DHCP.
+ //
+ status = GetIPFromRegistry(
+ pucRegistryPath,
+ pucBindName,
+ &ulIpAddress,
+ &ulSubnetMask,
+ TRUE);
+ }
+#endif NOTYET_PNP
+#endif // _PNP_POWER
+
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Nbt!GetIPFromRegistry returned status=%X\n",status));
+ return(status);
+ }
+
+#ifdef _PNP_POWER
+
+ //
+ // Now, we create all devices up-front (in driverentry); so no need to open the addresses etc.
+ //
+ return(status);
+#endif
+
+ // get the ip address out of the registry and open the required address
+ // objects with the underlying transport provider
+ status = NbtCreateAddressObjects(
+ ulIpAddress,
+ ulSubnetMask,
+ pDeviceContext);
+
+ if (!NT_SUCCESS(status))
+ {
+ NbtLogEvent(EVENT_NBT_CREATE_ADDRESS,status);
+
+ KdPrint(("Failed to create the Address Object, status=%X\n",status));
+
+ return(status);
+ }
+
+ //
+ // Add the "permanent" name to the local name table. This is the IP
+ // address of the node padded out to 16 bytes with zeros.
+ //
+ status = NbtAddPermanentName(pDeviceContext);
+
+ // this call must converse with the transport underneath to create
+ // connections and associate them with the session address object
+ status = NbtInitConnQ(
+ &pDeviceContext->LowerConnFreeHead,
+ sizeof(tLOWERCONNECTION),
+ NBT_NUM_INITIAL_CONNECTIONS,
+ pDeviceContext);
+
+ if (!NT_SUCCESS(status))
+ {
+ // NEED TO PUT CODE IN HERE TO RELEASE THE DEVICE OBJECT CREATED
+ // ABOVE AND LOG AN ERROR...
+
+ NbtLogEvent(EVENT_NBT_CREATE_CONNECTION,status);
+
+ KdPrint(("Failed to create the Connection Queue, status=%X\n",status));
+
+ return(status);
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+/*******************************************************************
+
+ NAME: NbtMarkHandlesAsStale
+
+ SYNOPSIS: Marks all open handles on this device as stale
+
+ ENTRY: DeviceContext ptr
+
+ NOTE: Should be called with NbtConfig.JointLock held.
+
+ HISTORY:
+ SanjayAn 11-Sept.-1996 Created
+
+********************************************************************/
+VOID
+NbtMarkHandlesAsStale (
+ IN tDEVICECONTEXT * pDeviceContext
+ )
+{
+ CTELockHandle OldIrq1;
+ CTELockHandle OldIrq2;
+ CTELockHandle OldIrq3;
+ CTELockHandle OldIrq4;
+ PLIST_ENTRY pEntry;
+ PLIST_ENTRY pEntry1;
+ PLIST_ENTRY pEntry2;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pHead1;
+ PLIST_ENTRY pHead2;
+ tADDRESSELE *pAddressEle;
+ tCONNECTELE *pConnEle;
+ tCLIENTELE *pClient;
+
+ // go through the list of addresses, then the list of clients on each
+ // address and then the list of connection that are in use and those that
+ // are currently Listening.
+ //
+ pHead = &NbtConfig.AddressHead;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
+
+ CTESpinLock(pAddressEle,OldIrq2);
+
+ if (pAddressEle->pDeviceContext != pDeviceContext) {
+ CTESpinFree(pAddressEle,OldIrq2);
+ pEntry = pEntry->Flink;
+ continue;
+ }
+
+ pHead1 = &pAddressEle->ClientHead;
+ pEntry1 = pHead1->Flink;
+ while (pEntry1 != pHead1)
+ {
+ pClient = CONTAINING_RECORD(pEntry1,tCLIENTELE,Linkage);
+ pEntry1 = pEntry1->Flink;
+
+ CTESpinLock(pClient,OldIrq3);
+
+ ASSERT(pClient->pDeviceContext == pDeviceContext);
+
+ //
+ // Mark ClientEle as down so only a close is valid on it.
+ //
+ pClient->Verify = NBT_VERIFY_CLIENT_DOWN;
+
+ pHead2 = &pClient->ConnectActive;
+ pEntry2 = pHead2->Flink;
+ while (pEntry2 != pHead2)
+ {
+ //
+ // Mark ConnEle as down so only a close is valid on it.
+ //
+ pConnEle = CONTAINING_RECORD(pEntry2,tCONNECTELE,Linkage);
+
+ CTESpinLock(pConnEle,OldIrq4);
+
+ ASSERT(pConnEle->pDeviceContext == pDeviceContext);
+
+ pConnEle->Verify = NBT_VERIFY_CONNECTION_DOWN;
+
+ CTESpinFree(pConnEle,OldIrq4);
+
+ pEntry2 = pEntry2->Flink;
+ }
+
+ pHead2 = &pClient->ConnectActive;
+ pEntry2 = pHead2->Flink;
+ while (pEntry2 != pHead2)
+ {
+ tLISTENREQUESTS *pListenReq;
+
+ //
+ // Mark ConnEle as down so only a close is valid on it.
+ //
+ pListenReq = CONTAINING_RECORD(pEntry2,tLISTENREQUESTS,Linkage);
+ pConnEle = (tCONNECTELE *)pListenReq->pConnectEle;
+
+ CTESpinLock(pConnEle,OldIrq4);
+
+ ASSERT(pConnEle->pDeviceContext == pDeviceContext);
+
+ pConnEle->Verify = NBT_VERIFY_CONNECTION_DOWN;
+
+ CTESpinFree(pConnEle,OldIrq4);
+
+ pEntry2 = pEntry2->Flink;
+ }
+ CTESpinFree(pClient,OldIrq3);
+ }
+ CTESpinFree(pAddressEle,OldIrq2);
+ pEntry = pEntry->Flink;
+ }
+}
+#endif
+
+/*******************************************************************
+
+ NAME: NbtDestroyDeviceObject
+
+ SYNOPSIS: Destroys the specified device
+
+ ENTRY: pBuffer - name of the device/ device ptr
+
+ HISTORY:
+ SanjayAn 11-Sept.-1996 Created
+
+********************************************************************/
+
+NTSTATUS
+NbtDestroyDeviceObject(
+#if 0
+ IN PVOID pBuffer
+#endif
+ IN tDEVICECONTEXT * pDeviceContext
+ )
+{
+ LIST_ENTRY * pEntry;
+ LIST_ENTRY * pHead;
+ tDEVICECONTEXT * pTmpDeviceContext;
+ tDEVICECONTEXT * pNextDeviceContext;
+ tCLIENTELE * pClientEle;
+ tADDRESSELE * pAddress;
+ tNAMEADDR * pNameAddr;
+ tCONNECTELE * pConnEle;
+ tLOWERCONNECTION * pLowerConn;
+ tTIMERQENTRY * pTimer;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+ tDGRAM_SEND_TRACKING * pTracker;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ CTELockHandle OldIrq2;
+ int i;
+ tNBTCONFIG *pConfig = &NbtConfig;
+ WCHAR Buffer[MAX_PATH];
+ UNICODE_STRING ucExportName;
+ PUNICODE_STRING pucExportName;
+
+#if 0
+ tDEVICECONTEXT * pDeviceContext;
+
+ ucExportName.MaximumLength = sizeof(Buffer);
+ ucExportName.Buffer = Buffer;
+ pucExportName = &ucExportName;
+
+ RtlInitUnicodeString(pucExportName, &((PNETBT_ADD_DEL_IF)pBuffer)->IfName[0]);
+
+ //
+ // Find which device is going away
+ // Also, find out a device object that is still active: we need that info
+ // to update some of the address ele's.
+ //
+ pDeviceContext = NULL;
+ pNextDeviceContext = NULL;
+
+ for ( pEntry = pConfig->DeviceContexts.Flink;
+ pEntry != &pConfig->DeviceContexts;
+ pEntry = pEntry->Flink )
+ {
+ pTmpDeviceContext = CONTAINING_RECORD( pEntry, tDEVICECONTEXT, Linkage);
+ if ( !RtlCompareUnicodeString (
+ &pTmpDeviceContext->ExportName,
+ pucExportName,
+ FALSE))
+ pDeviceContext = pTmpDeviceContext;
+ else
+ pNextDeviceContext = pTmpDeviceContext;
+ }
+#endif
+
+ if (pDeviceContext == NULL)
+ return STATUS_INVALID_PARAMETER;
+
+ if (pDeviceContext->IpAddress != 0) {
+ (VOID)NbtNewDhcpAddress(pDeviceContext,0,0);
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CTESpinLock(pDeviceContext,OldIrq1);
+
+ if ( --NbtConfig.AdapterCount == 1)
+ NbtConfig.MultiHomed = FALSE;
+
+ ASSERT(IsListEmpty(&pDeviceContext->LowerConnFreeHead));
+
+ //
+ // walk through all names and see if any is being registered on this
+ // device context: if so, stop and complete it!
+ //
+ for (i=0;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ )
+ {
+ pHead = &NbtConfig.pLocalHashTbl->Bucket[i];
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ pEntry = pEntry->Flink;
+
+ if (pNameAddr->NameTypeState & STATE_RESOLVING)
+ {
+ pTimer = pNameAddr->pTimer;
+
+ //
+ // if the name registration was started for this name on this device
+ // context, stop the timer. (Completion routine will take care of
+ // doing registration on other device contexts if applicable)
+ //
+ if (pTimer)
+ {
+ pTracker = pTimer->Context;
+ ASSERT(pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+ if (pTracker->pDeviceContext == pDeviceContext)
+ {
+ ASSERT(pTracker->pNameAddr == pNameAddr);
+
+ pNameAddr->pTimer = NULL;
+
+ StopTimer(pTimer,&pClientCompletion,&Context);
+
+ if (pClientCompletion)
+ {
+ (*pClientCompletion)(Context,STATUS_NETWORK_NAME_DELETED);
+ }
+
+ KdPrint(("DestroyDeviceObject: stopped name reg timer")) ;
+ }
+ }
+
+ }
+ }
+ }
+
+ //
+ // close all the TDI handles
+ //
+ CTESpinFree(pDeviceContext,OldIrq1);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ CloseAddressesWithTransport(pDeviceContext);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CTESpinLock(pDeviceContext,OldIrq1);
+
+ while (!IsListEmpty(&pDeviceContext->LowerConnection))
+ {
+ pEntry = RemoveHeadList(&pDeviceContext->LowerConnection);
+ pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
+ CTEMemFree( pLowerConn );
+ }
+
+ RemoveEntryList( &pDeviceContext->Linkage);
+
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ //
+ // IoDeleteDevice on a device with open handles is not supported currently.
+ // Until the base guys support this feature, we hack Netbt to never call IoDeleteDevice;
+ // instead we mark it as down and re-use the block on a later open.
+ // We also mark all open handles as invalid so we fail any request directed at them.
+ //
+ CTESpinFree(pDeviceContext,OldIrq1);
+ NbtMarkHandlesAsStale(pDeviceContext);
+ CTESpinLock(pDeviceContext,OldIrq1);
+#endif
+
+ //
+ // Walk through the AddressHead list. If any addresses exist and they
+ // point to old device context, put the next device context. Also, update
+ // adapter mask to reflect that this device context is now gone.
+ //
+ KdPrint(("DestroyDeviceObject: setting AddrEle,NameAddr fields\r\n"));
+ pHead = pEntry = &NbtConfig.AddressHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pAddress = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
+ ASSERT (pAddress->Verify == NBT_VERIFY_ADDRESS);
+ if (pAddress->pDeviceContext == pDeviceContext)
+ {
+ if (!IsListEmpty(&pConfig->DeviceContexts)) {
+ pAddress->pDeviceContext = CONTAINING_RECORD( pConfig->DeviceContexts.Flink, tDEVICECONTEXT, Linkage);
+ } else {
+ pAddress->pDeviceContext = NULL;
+ }
+ }
+
+ //
+ // Release the name on this adapter; but dont release on other adapters
+ //
+ // only release the name on the net if it was not in conflict first
+ // This prevents name releases going out for names that were not actually
+ // claimed. Also, quick add names are not released on the net either.
+ //
+ if (!(pNameAddr->NameTypeState & (STATE_CONFLICT | NAMETYPE_QUICK)) &&
+ (pAddress->pNameAddr->Name[0] != '*') &&
+ (pNameAddr->AdapterMask & pDeviceContext->AdapterNumber))
+ {
+ CTESpinFree(pDeviceContext,OldIrq1);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ (VOID)ReleaseNameOnNet(pAddress->pNameAddr,
+ NbtConfig.pScope,
+ pAddress,
+ NameReleaseDoneOnDynIf, // name released on dynamic if
+ NodeType,
+ pDeviceContext);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CTESpinLock(pDeviceContext,OldIrq1);
+ }
+ }
+
+ //
+ // Mark in the device extension that this is not a valid device. Default is FALSE...
+ //
+ InterlockedIncrement(&pDeviceContext->IsDestroyed);
+
+#ifndef _IO_DELETE_DEVICE_SUPPORTED
+ //
+ // Chain the device on the free list
+ //
+ ExInterlockedInsertTailList(&NbtConfig.FreeDevCtx,
+ &pDeviceContext->FreeLinkage,
+ &NbtConfig.SpinLock);
+
+ CTESpinFree(pDeviceContext,OldIrq1);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+#else
+
+ CTEMemFree( pDeviceContext->ExportName.Buffer );
+ CTESpinFree(pDeviceContext,OldIrq1);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext);
+
+#endif
+
+ KdPrint(("DestroyDeviceObject: deleted @ %lx\n", pDeviceContext));
+
+ return STATUS_SUCCESS;
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+CreateControlObject(
+ tNBTCONFIG *pConfig)
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory for the provider info block, tacks it
+ onto the global configuration and sets default values for each item.
+
+Arguments:
+
+
+Return Value:
+
+
+ NTSTATUS
+
+--*/
+
+{
+ tCONTROLOBJECT *pControl;
+
+
+ CTEPagedCode();
+ pControl = (tCONTROLOBJECT *)ExAllocatePool(
+ NonPagedPool,
+ sizeof(tCONTROLOBJECT));
+ if (!pControl)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pControl->Verify = NBT_VERIFY_CONTROL;
+
+ // setup the spin lock);
+ CTEInitLock(&pControl->SpinLock);
+
+ pControl->ProviderInfo.Version = 1;
+ pControl->ProviderInfo.MaxSendSize = 0;
+ pControl->ProviderInfo.MaxConnectionUserData = 0;
+
+ // we need to get these values from the transport underneath...*TODO*
+ // since the RDR uses this value
+ pControl->ProviderInfo.MaxDatagramSize = 0;
+
+ pControl->ProviderInfo.ServiceFlags = 0;
+/* pControl->ProviderInfo.TransmittedTsdus = 0;
+ pControl->ProviderInfo.ReceivedTsdus = 0;
+ pControl->ProviderInfo.TransmissionErrors = 0;
+ pControl->ProviderInfo.ReceiveErrors = 0;
+*/
+ pControl->ProviderInfo.MinimumLookaheadData = 0;
+ pControl->ProviderInfo.MaximumLookaheadData = 0;
+/* pControl->ProviderInfo.DiscardedFrames = 0;
+ pControl->ProviderInfo.OversizeTsdusReceived = 0;
+ pControl->ProviderInfo.UndersizeTsdusReceived = 0;
+ pControl->ProviderInfo.MulticastTsdusReceived = 0;
+ pControl->ProviderInfo.BroadcastTsdusReceived = 0;
+ pControl->ProviderInfo.MulticastTsdusTransmitted = 0;
+ pControl->ProviderInfo.BroadcastTsdusTransmitted = 0;
+ pControl->ProviderInfo.SendTimeouts = 0;
+ pControl->ProviderInfo.ReceiveTimeouts = 0;
+ pControl->ProviderInfo.ConnectionIndicationsReceived = 0;
+ pControl->ProviderInfo.ConnectionIndicationsAccepted = 0;
+ pControl->ProviderInfo.ConnectionsInitiated = 0;
+ pControl->ProviderInfo.ConnectionsAccepted = 0;
+*/
+ // put a ptr to this info into the pConfig so we can locate it
+ // when we want to cleanup
+ pConfig->pControlObj = pControl;
+
+ /* KEEP THIS STUFF HERE SINCE WE MAY NEED TO ALSO CREATE PROVIDER STATS!!
+ *TODO*
+ DeviceList[i].ProviderStats.Version = 2;
+ DeviceList[i].ProviderStats.OpenConnections = 0;
+ DeviceList[i].ProviderStats.ConnectionsAfterNoRetry = 0;
+ DeviceList[i].ProviderStats.ConnectionsAfterRetry = 0;
+ DeviceList[i].ProviderStats.LocalDisconnects = 0;
+ DeviceList[i].ProviderStats.RemoteDisconnects = 0;
+ DeviceList[i].ProviderStats.LinkFailures = 0;
+ DeviceList[i].ProviderStats.AdapterFailures = 0;
+ DeviceList[i].ProviderStats.SessionTimeouts = 0;
+ DeviceList[i].ProviderStats.CancelledConnections = 0;
+ DeviceList[i].ProviderStats.RemoteResourceFailures = 0;
+ DeviceList[i].ProviderStats.LocalResourceFailures = 0;
+ DeviceList[i].ProviderStats.NotFoundFailures = 0;
+ DeviceList[i].ProviderStats.NoListenFailures = 0;
+
+ DeviceList[i].ProviderStats.DatagramsSent = 0;
+ DeviceList[i].ProviderStats.DatagramBytesSent.HighPart = 0;
+ DeviceList[i].ProviderStats.DatagramBytesSent.LowPart = 0;
+
+ DeviceList[i].ProviderStats.DatagramsReceived = 0;
+ DeviceList[i].ProviderStats.DatagramBytesReceived.HighPart = 0;
+ DeviceList[i].ProviderStats.DatagramBytesReceived.LowPart = 0;
+
+ DeviceList[i].ProviderStats.PacketsSent = 0;
+ DeviceList[i].ProviderStats.PacketsReceived = 0;
+
+ DeviceList[i].ProviderStats.DataFramesSent = 0;
+ DeviceList[i].ProviderStats.DataFrameBytesSent.HighPart = 0;
+ DeviceList[i].ProviderStats.DataFrameBytesSent.LowPart = 0;
+
+ DeviceList[i].ProviderStats.DataFramesReceived = 0;
+ DeviceList[i].ProviderStats.DataFrameBytesReceived.HighPart = 0;
+ DeviceList[i].ProviderStats.DataFrameBytesReceived.LowPart = 0;
+
+ DeviceList[i].ProviderStats.DataFramesResent = 0;
+ DeviceList[i].ProviderStats.DataFrameBytesResent.HighPart = 0;
+ DeviceList[i].ProviderStats.DataFrameBytesResent.LowPart = 0;
+
+ DeviceList[i].ProviderStats.DataFramesRejected = 0;
+ DeviceList[i].ProviderStats.DataFrameBytesRejected.HighPart = 0;
+ DeviceList[i].ProviderStats.DataFrameBytesRejected.LowPart = 0;
+
+ DeviceList[i].ProviderStats.ResponseTimerExpirations = 0;
+ DeviceList[i].ProviderStats.AckTimerExpirations = 0;
+ DeviceList[i].ProviderStats.MaximumSendWindow = 0;
+ DeviceList[i].ProviderStats.AverageSendWindow = 0;
+ DeviceList[i].ProviderStats.PiggybackAckQueued = 0;
+ DeviceList[i].ProviderStats.PiggybackAckTimeouts = 0;
+
+ DeviceList[i].ProviderStats.WastedPacketSpace.HighPart = 0;
+ DeviceList[i].ProviderStats.WastedPacketSpace.LowPart = 0;
+ DeviceList[i].ProviderStats.WastedSpacePackets = 0;
+ DeviceList[i].ProviderStats.NumberOfResources = 0;
+ */
+ return(STATUS_SUCCESS);
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+IfNotAnyLowerConnections(
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine checks each device context to see if there are any open
+ connections, and returns SUCCESS if there are. If the DoDisable flag
+ is set the list head of free lower connections is returned and the
+ list in the Nbtconfig structure is made empty.
+
+Arguments:
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+
+ CTESpinLock(pDeviceContext,OldIrq);
+ if (!IsListEmpty(&pDeviceContext->LowerConnection))
+ {
+ CTESpinFree(pDeviceContext,OldIrq);
+ return(STATUS_UNSUCCESSFUL);
+ }
+ CTESpinFree(pDeviceContext,OldIrq);
+ return(STATUS_SUCCESS);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+CloseAddressesWithTransport(
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine checks each device context to see if there are any open
+ connections, and returns SUCCESS if there are.
+
+Arguments:
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ BOOLEAN Attached;
+ CTELockHandle OldIrq;
+ PFILE_OBJECT pNSFileObject, pSFileObject, pDGFileObject;
+
+ CTEAttachFsp(&Attached);
+
+ //
+ // Check for the existence of Objects under SpinLock and
+ // then Close them outside of the SpinLock
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ if (pNSFileObject = pDeviceContext->pNameServerFileObject)
+ {
+ pDeviceContext->pNameServerFileObject = NULL;
+ }
+ if (pSFileObject = pDeviceContext->pSessionFileObject)
+ {
+ pDeviceContext->pSessionFileObject = NULL;
+ }
+ if (pDGFileObject = pDeviceContext->pDgramFileObject)
+ {
+ pDeviceContext->pDgramFileObject = NULL;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // Now close all the necessary objects as appropriate
+ //
+ if (pNSFileObject)
+ {
+ ObDereferenceObject((PVOID *)pNSFileObject);
+ ZwClose(pDeviceContext->hNameServer);
+ }
+ if (pSFileObject)
+ {
+ ObDereferenceObject((PVOID *)pSFileObject);
+ ZwClose(pDeviceContext->hSession);
+ }
+ if (pDGFileObject)
+ {
+ ObDereferenceObject((PVOID *)pDGFileObject);
+ ZwClose(pDeviceContext->hDgram);
+ }
+
+ CTEDetachFsp(Attached);
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtCreateAddressObjects(
+ IN ULONG IpAddress,
+ IN ULONG SubnetMask,
+ OUT tDEVICECONTEXT *pDeviceContext)
+
+/*++
+
+Routine Description:
+
+ This routine gets the ip address and subnet mask out of the registry
+ to calcuate the broadcast address. It then creates the address objects
+ with the transport.
+
+Arguments:
+
+ pucRegistryPath - path to NBT config info in registry
+ pucBindName - name of the service to bind to.
+ pDeviceContext - ptr to the device context... place to store IP addr
+ and Broadcast address permanently
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG ValueMask;
+ UCHAR IpAddrByte;
+
+ CTEPagedCode();
+ //
+ // to get the broadcast address combine the IP address with the subnet mask
+ // to yield a value with 1's in the "local" portion and the IP address
+ // in the network portion
+ //
+ ValueMask = (SubnetMask & IpAddress) | (~SubnetMask & -1);
+
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Broadcastaddress = %X\n",ValueMask));
+
+ //
+ // the registry can be configured to set the subnet broadcast address to
+ // -1 rather than use the actual subnet broadcast address. This code
+ // checks for that and sets the broadcast address accordingly.
+ //
+ if (!NbtConfig.UseRegistryBcastAddr)
+ {
+ pDeviceContext->BroadcastAddress = ValueMask;
+ }
+ else
+ {
+ pDeviceContext->BroadcastAddress = NbtConfig.RegistryBcastAddr;
+ }
+
+ pDeviceContext->IpAddress = IpAddress;
+
+ pDeviceContext->SubnetMask = SubnetMask;
+ //
+ // get the network number by checking the top bits in the ip address,
+ // looking for 0 or 10 or 110 or 1110
+ //
+ IpAddrByte = ((PUCHAR)&IpAddress)[3];
+ if ((IpAddrByte & 0x80) == 0)
+ {
+ // class A address - one byte netid
+ IpAddress &= 0xFF000000;
+ }
+ else
+ if ((IpAddrByte & 0xC0) ==0x80)
+ {
+ // class B address - two byte netid
+ IpAddress &= 0xFFFF0000;
+ }
+ else
+ if ((IpAddrByte & 0xE0) ==0xC0)
+ {
+ // class C address - three byte netid
+ IpAddress &= 0xFFFFFF00;
+ }
+
+
+ pDeviceContext->NetMask = IpAddress;
+
+
+ // now create the address objects.
+
+ // open the Ip Address for inbound Datagrams.
+ status = NbtTdiOpenAddress(
+ &pDeviceContext->hDgram,
+ &pDeviceContext->pDgramDeviceObject,
+ &pDeviceContext->pDgramFileObject,
+ pDeviceContext,
+ (USHORT)NBT_DATAGRAM_UDP_PORT,
+ pDeviceContext->IpAddress,
+ 0); // not a TCP port
+
+ if (NT_SUCCESS(status))
+ {
+ // open the Nameservice UDP port ..
+ status = NbtTdiOpenAddress(
+ &pDeviceContext->hNameServer,
+ &pDeviceContext->pNameServerDeviceObject,
+ &pDeviceContext->pNameServerFileObject,
+ pDeviceContext,
+ (USHORT)NBT_NAMESERVICE_UDP_PORT,
+ pDeviceContext->IpAddress,
+ 0); // not a TCP port
+
+ if (NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Nbt: Open Session port %X\n",pDeviceContext));
+
+ // Open the TCP port for Session Services
+ status = NbtTdiOpenAddress(
+ &pDeviceContext->hSession,
+ &pDeviceContext->pSessionDeviceObject,
+ &pDeviceContext->pSessionFileObject,
+ pDeviceContext,
+ (USHORT)NBT_SESSION_TCP_PORT,
+ pDeviceContext->IpAddress,
+ TCP_FLAG | SESSION_FLAG); // TCP port
+
+ if (NT_SUCCESS(status))
+ {
+ //
+ // This will get the MAC address for a RAS connection
+ // which is zero until there really is a connection to
+ // the RAS server
+ //
+ GetExtendedAttributes(pDeviceContext);
+ return(status);
+ }
+
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Unable to Open Session address with TDI, status = %X\n",status));
+
+ //
+ // Ensure that the Object pointers are NULLed out!
+ //
+ pDeviceContext->pSessionFileObject = NULL;
+
+ ObDereferenceObject(pDeviceContext->pNameServerFileObject);
+ pDeviceContext->pNameServerFileObject = NULL;
+ NTZwCloseFile(pDeviceContext->hNameServer);
+
+ }
+ ObDereferenceObject(pDeviceContext->pDgramFileObject);
+ pDeviceContext->pDgramFileObject = NULL;
+ NTZwCloseFile(pDeviceContext->hDgram);
+
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Unable to Open NameServer port with TDI, status = %X\n",status));
+ }
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+GetExtendedAttributes(
+ tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine converts a unicode dotted decimal to a ULONG
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ NTSTATUS status;
+ TCP_REQUEST_QUERY_INFORMATION_EX QueryReq;
+ UCHAR pBuffer[256];
+ IO_STATUS_BLOCK IoStatus;
+ ULONG BufferSize = 256;
+ HANDLE event;
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PWSTR pName=L"Tcp";
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ UNICODE_STRING DeviceName;
+ BOOLEAN Attached = FALSE;
+ HANDLE hTcp;
+
+ CTEPagedCode();
+
+ //
+ // Open a control channel to TCP for this IOCTL.
+ //
+ // NOTE: We cannot use the hControl in the DeviceContext since that was created in the context
+ // of the system process (address arrival from TCP/IP). Here, we are in the context of the service
+ // process (Ioctl down from DHCP) and so we need to open another control channel.
+ //
+ // NOTE: We still need to maintain the earlier call to create a control channel since that is
+ // used to submit TDI requests down to TCP/IP.
+ //
+
+ // copy device name into the unicode string
+ Status = CreateDeviceString(pName,&DeviceName);
+ if (!NT_SUCCESS(Status))
+ {
+ return;
+ }
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ &DeviceName,
+ 0,
+ NULL,
+ NULL);
+
+ IF_DBG(NBT_DEBUG_TDIADDR)
+ KdPrint(("tcp device to open = %ws\n",DeviceName.Buffer));
+
+ EaBuffer = NULL;
+
+ Status = ZwCreateFile (
+ &hTcp,
+ GENERIC_READ | GENERIC_WRITE,
+ &ObjectAttributes, // object attributes.
+ &IoStatusBlock, // returned status information.
+ NULL, // block size (unused).
+ FILE_ATTRIBUTE_NORMAL, // file attributes.
+ 0,
+ FILE_CREATE,
+ 0, // create options.
+ (PVOID)EaBuffer, // EA buffer.
+ 0); // Ea length
+
+
+ CTEMemFree(DeviceName.Buffer);
+
+ IF_DBG(NBT_DEBUG_TDIADDR)
+ KdPrint( ("OpenControl CreateFile Status:%X, IoStatus:%X\n", Status, IoStatusBlock.Status));
+
+ if ( NT_SUCCESS( Status ))
+ {
+ //
+ // Initialize the TDI information buffers.
+ //
+ //
+ // pass in the ipaddress as the first ULONG of the context array
+ //
+ *(ULONG *)QueryReq.Context = htonl(pDeviceContext->IpAddress);
+
+ QueryReq.ID.toi_entity.tei_entity = CL_NL_ENTITY;
+ QueryReq.ID.toi_entity.tei_instance = 0;
+ QueryReq.ID.toi_class = INFO_CLASS_PROTOCOL;
+ QueryReq.ID.toi_type = INFO_TYPE_PROVIDER;
+ QueryReq.ID.toi_id = IP_INTFC_INFO_ID;
+
+ status = ZwCreateEvent(
+ &event,
+ EVENT_ALL_ACCESS,
+ NULL,
+ SynchronizationEvent,
+ FALSE
+ );
+
+ if ( !NT_SUCCESS(status) )
+ {
+ return;
+
+ }
+
+ //
+ // Make the actual TDI call
+ //
+
+ status = ZwDeviceIoControlFile(
+ hTcp,
+ event,
+ NULL,
+ NULL,
+ &IoStatus,
+ IOCTL_TCP_QUERY_INFORMATION_EX,
+ &QueryReq,
+ sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
+ pBuffer,
+ BufferSize
+ );
+
+ //
+ // If the call pended and we were supposed to wait for completion,
+ // then wait.
+ //
+
+ if ( status == STATUS_PENDING )
+ {
+ status = KeWaitForSingleObject( event, Executive, KernelMode, FALSE, NULL );
+
+ ASSERT( NT_SUCCESS(status) );
+ }
+
+ if ( NT_SUCCESS(status) )
+ {
+ ULONG Length;
+
+ pDeviceContext->PointToPoint = ((((IPInterfaceInfo *)pBuffer)->iii_flags & IP_INTFC_FLAG_P2P) != 0);
+
+ //
+ // get the length of the mac address in case is is less than
+ // 6 bytes
+ //
+ Length = (((IPInterfaceInfo *)pBuffer)->iii_addrlength < sizeof(tMAC_ADDRESS))
+ ? ((IPInterfaceInfo *)pBuffer)->iii_addrlength : sizeof(tMAC_ADDRESS);
+
+ CTEZeroMemory(pDeviceContext->MacAddress.Address,sizeof(tMAC_ADDRESS));
+ CTEMemCopy(&pDeviceContext->MacAddress.Address[0],
+ ((IPInterfaceInfo *)pBuffer)->iii_addr,
+ Length);
+
+ }
+
+ status = ZwClose( event );
+ ASSERT( NT_SUCCESS(status) );
+
+ status = IoStatus.Status;
+
+ //
+ // Close the handle to TCP since we dont need it anymore; all TDI requests go thru the
+ // Control handle in the DeviceContext.
+ //
+ status = ZwClose( hTcp );
+ ASSERT( NT_SUCCESS(status) );
+ }
+ else
+ {
+ KdPrint(("Nbt:Failed to Open the control connection to the transport, status1 = %X\n",
+ Status));
+
+ }
+
+ return;
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+ConvertToUlong(
+ IN PUNICODE_STRING pucAddress,
+ OUT ULONG *pulValue)
+
+/*++
+
+Routine Description:
+
+ This routine converts a unicode dotted decimal to a ULONG
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ NTSTATUS status;
+ OEM_STRING OemAddress;
+
+ // create integer from unicode string
+
+ CTEPagedCode();
+ status = RtlUnicodeStringToAnsiString(&OemAddress, pucAddress, TRUE);
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+
+ status = ConvertDottedDecimalToUlong(OemAddress.Buffer,pulValue);
+
+ RtlFreeAnsiString(&OemAddress);
+
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("ERR: Bad Dotted Decimal Ip Address(must be <=255 with 4 dots) = %ws\n",
+ pucAddress->Buffer));
+
+ return(status);
+ }
+
+ return(STATUS_SUCCESS);
+
+
+}
+
+
+
+//----------------------------------------------------------------------------
+ VOID
+NbtGetMdl(
+ PMDL *ppMdl,
+ enum eBUFFER_TYPES eBuffType)
+
+/*++
+
+Routine Description:
+
+ This routine allocates an Mdl.
+
+Arguments:
+
+ ppListHead - a ptr to a ptr to the list head to add buffer to
+ iNumBuffers - the number of buffers to add to the queue
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ PMDL pMdl;
+ ULONG lBufferSize;
+ PVOID pBuffer;
+
+ if (NbtConfig.iCurrentNumBuff[eBuffType]
+ >= NbtConfig.iMaxNumBuff[eBuffType])
+ {
+ *ppMdl = NULL;
+ return;
+ }
+
+ lBufferSize = NbtConfig.iBufferSize[eBuffType];
+
+ pBuffer = NbtAllocMem((USHORT)lBufferSize,NBT_TAG('g'));
+
+ if (!pBuffer)
+ {
+ *ppMdl = NULL;
+ return;
+ }
+
+ // allocate a MDL to hold the session hdr
+ pMdl = IoAllocateMdl(
+ (PVOID)pBuffer,
+ lBufferSize,
+ FALSE, // want this to be a Primary buffer - the first in the chain
+ FALSE,
+ NULL);
+
+ *ppMdl = pMdl;
+
+ if (!pMdl)
+ {
+ CTEMemFree(pBuffer);
+ return;
+ }
+
+ // fill in part of the session hdr since it is always the same
+ if (eBuffType == eNBT_FREE_SESSION_MDLS)
+ {
+ ((tSESSIONHDR *)pBuffer)->Flags = NBT_SESSION_FLAGS;
+ ((tSESSIONHDR *)pBuffer)->Type = NBT_SESSION_MESSAGE;
+ }
+ else
+ if (eBuffType == eNBT_DGRAM_MDLS)
+ {
+ ((tDGRAMHDR *)pBuffer)->Flags = FIRST_DGRAM | (NbtConfig.PduNodeType >> 10);
+ ((tDGRAMHDR *)pBuffer)->PckOffset = 0; // not fragmented
+
+ }
+
+ // map the Mdl properly to fill in the pages portion of the MDL
+ MmBuildMdlForNonPagedPool(pMdl);
+
+ NbtConfig.iCurrentNumBuff[eBuffType]++;
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtInitMdlQ(
+ PSINGLE_LIST_ENTRY pListHead,
+ enum eBUFFER_TYPES eBuffType)
+
+/*++
+
+Routine Description:
+
+ This routine allocates Mdls for use later.
+
+Arguments:
+
+ ppListHead - a ptr to a ptr to the list head to add buffer to
+ iNumBuffers - the number of buffers to add to the queue
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ int i;
+ PMDL pMdl;
+
+
+ CTEPagedCode();
+ // Initialize the list head, so the last element always points to NULL
+ pListHead->Next = NULL;
+
+ // create a small number first and then lis the list grow with time
+ for (i=0;i < NBT_INITIAL_NUM ;i++ )
+ {
+
+ NbtGetMdl(&pMdl,eBuffType);
+ if (!pMdl)
+ {
+ KdPrint(("NBT:Unable to allocate MDL at initialization time!!\n"));\
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // put on free list
+ PushEntryList(pListHead,(PSINGLE_LIST_ENTRY)pMdl);
+
+ }
+
+ return(STATUS_SUCCESS);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTZwCloseFile(
+ IN HANDLE Handle
+ )
+
+/*++
+Routine Description:
+
+ This Routine handles closing a handle with NT within the context of NBT's
+ file system process.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ BOOLEAN Attached = FALSE;
+
+ CTEPagedCode();
+ //
+ // Attach to NBT's FSP (file system process) to free the handle since
+ // the handle is only valid in that process.
+ //
+ if (PsGetCurrentProcess() != NbtFspProcess)
+ {
+ KeAttachProcess(&NbtFspProcess->Pcb);
+ Attached = TRUE;
+ }
+
+ status = ZwClose(Handle);
+
+ if (Attached)
+ {
+ //
+ // go back to the original process
+ //
+ KeDetachProcess();
+ }
+
+ return(status);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTReReadRegistry(
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+
+/*++
+Routine Description:
+
+ This Routine re-reads the registry values when DHCP issues the Ioctl
+ to do so.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ tADDRARRAY *pAddrArray=NULL;
+ tADDRARRAY *pAddr;
+ tDEVICES *pBindDevices=NULL;
+ tDEVICES *pExportDevices=NULL;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ tDEVICECONTEXT *pDevContext;
+
+ CTEPagedCode();
+
+ CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
+
+ //
+ // BUGBUG [WishList]: We look at the whole registry in NbtAddressAdd too.
+ //
+ status = NbtReadRegistry(
+ &NbtConfig.pRegistry,
+ NULL, // Null Driver Object
+ &NbtConfig,
+ &pBindDevices,
+ &pExportDevices,
+ &pAddrArray);
+
+ if (pAddrArray)
+ {
+ ULONG i;
+#if DBG
+ {
+ BOOLEAN fFound=FALSE;
+
+ //
+ // Loop thru the devicecontexts in the Config struct to ensure that this DeviceContext
+ // is actually valid.
+ //
+ // BUGBUG[WishList]:Would be good to have signatures in the structures.
+ //
+ pAddr = pAddrArray;
+ pHead = &NbtConfig.DeviceContexts;
+ pEntry = pHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+ if (pDevContext == pDeviceContext)
+ {
+ fFound = TRUE;
+ break;
+ }
+ }
+
+ ASSERT(fFound == TRUE);
+ }
+#endif
+
+ //
+ // Figure out the Address entry by matching the BindDevice names against the
+ // name in the DeviceContext passed in.
+ //
+ for (i=0; i<NbtConfig.uNumDevices; i++) {
+
+ if (RtlCompareUnicodeString(&pDeviceContext->BindName,
+ &pBindDevices->Names[i],
+ FALSE) == 0) {
+ //
+ // We found a match
+ //
+ pDeviceContext->lNameServerAddress = pAddrArray[i].NameServerAddress;
+ pDeviceContext->lBackupServer = pAddrArray[i].BackupServer;
+
+ //
+ // if the node type is set to Bnode by default then switch to Hnode if
+ // there are any WINS servers configured.
+ //
+ if ((NodeType & DEFAULT_NODE_TYPE) &&
+ (pAddrArray[i].NameServerAddress || pAddrArray[i].BackupServer))
+ {
+ NodeType = MSNODE | (NodeType & PROXY);
+ }
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("NBT:Found BindName: %lx, AddrArray: %lx, i: %lx\n", pBindDevices, pAddrArray, i));
+
+ break;
+ }
+ }
+
+#if DBG
+ if (i == NbtConfig.uNumDevices) {
+ KdPrint(("Nbt:Unable to find the entry corresp. to device %lx in the registry. BindDevices: %lx\n",
+ pDeviceContext, pBindDevices));
+ DbgBreakPoint();
+ }
+#endif
+ }
+
+ //
+ // Free Allocated memory
+ //
+ if (pBindDevices)
+ {
+ CTEMemFree(pBindDevices->RegistrySpace);
+ CTEMemFree((PVOID)pBindDevices);
+ }
+ if (pExportDevices)
+ {
+ CTEMemFree(pExportDevices->RegistrySpace);
+ CTEMemFree((PVOID)pExportDevices);
+ }
+ if (pAddrArray)
+ {
+ CTEMemFree((PVOID)pAddrArray);
+ }
+
+ CTEExReleaseResource(&NbtConfig.Resource);
+
+ if (pDeviceContext->IpAddress)
+ {
+ //
+ // Add the "permanent" name to the local name table. This is the IP
+ // address of the node padded out to 16 bytes with zeros.
+ //
+ status = NbtAddPermanentName(pDeviceContext);
+
+ if (!(NodeType & BNODE))
+ {
+ // Probably the Ip address just changed and Dhcp is informing us
+ // of a new Wins Server addresses, so refresh all the names to the
+ // new wins server
+ //
+ ReRegisterLocalNames();
+ }
+ else
+ {
+ //
+ // no need to refresh
+ // on a Bnode
+ //
+ LockedStopTimer(&NbtConfig.pRefreshTimer);
+ }
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtLogEvent(
+ IN ULONG EventCode,
+ IN NTSTATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates an I/O error log record, fills it in and writes it
+ to the I/O error log.
+
+
+Arguments:
+
+ EventCode - Identifies the error message.
+ Status - The status value to log: this value is put into the
+ data portion of the log message.
+
+
+Return Value:
+
+ STATUS_SUCCESS - The error was successfully logged..
+ STATUS_BUFER_OVERFLOW - The error data was too large to be logged.
+ STATUS_INSUFFICIENT_RESOURCES - Unable to allocate memory.
+
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET ErrorLogEntry;
+ PVOID LoggingObject;
+
+ LoggingObject = NbtConfig.DriverObject;
+
+ ErrorLogEntry = IoAllocateErrorLogEntry(LoggingObject,sizeof(IO_ERROR_LOG_PACKET));
+
+ if (ErrorLogEntry == NULL)
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Unalbe to allocate Error Packet for Error logging\n"));
+
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // Fill in the necessary log packet fields.
+ //
+ ErrorLogEntry->UniqueErrorValue = 0;
+ ErrorLogEntry->ErrorCode = EventCode;
+ ErrorLogEntry->NumberOfStrings = 0;
+ ErrorLogEntry->StringOffset = 0;
+ ErrorLogEntry->DumpDataSize = (USHORT)sizeof(ULONG);
+ ErrorLogEntry->DumpData[0] = Status;
+
+ IoWriteErrorLogEntry(ErrorLogEntry);
+
+ return(STATUS_SUCCESS);
+}
+#ifdef DBGMEMNBT
+VOID
+PadEntry(
+ char *EntryPtr
+ )
+{
+ char *Limit;
+
+ //
+ // pad remainder of entry
+ //
+ Limit = EntryPtr + LOGWIDTH - 1;
+ ASSERT(LOGWIDTH >= (strlen(EntryPtr) + 1));
+ for (EntryPtr += strlen(EntryPtr);
+ EntryPtr != Limit;
+ EntryPtr++
+ ) {
+ *EntryPtr = ' ';
+ }
+ *EntryPtr = '\0';
+}
+//----------------------------------------------------------------------------
+ PVOID
+CTEAllocMemDebug(
+ IN ULONG Size,
+ IN PVOID pBuffer,
+ IN UCHAR *File,
+ IN ULONG Line
+ )
+
+/*++
+
+Routine Description:
+
+ This function logs getting and freeing memory.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CCHAR CurrProc;
+ UCHAR LockFree;
+ UCHAR *EntryPtr;
+ char *Limit;
+ PUCHAR pFile;
+ PVOID pMem;
+ PSTRM_PROCESSOR_LOG Log ;
+
+
+ if (!pBuffer)
+ {
+ if (!LogAlloc)
+ {
+ LogAlloc = ExAllocatePool(NonPagedPool,sizeof(STRM_PROCESSOR_LOG));
+ LogAlloc->Index = 0;
+ }
+ Log = LogAlloc;
+ pMem = ExAllocatePool(NonPagedPool,Size);
+ }
+ else
+ {
+ if (!LogFree)
+ {
+ LogFree = ExAllocatePool(NonPagedPool,sizeof(STRM_PROCESSOR_LOG));
+ LogFree->Index = 0;
+ }
+ Log = LogFree;
+ pMem = pBuffer;
+ ExFreePool(pBuffer);
+ }
+
+ EntryPtr = Log->Log[Log->Index];
+
+ pFile = strrchr(File,'\\');
+
+ sprintf(EntryPtr,"%s %d %X",pFile, Line,pMem);
+
+ PadEntry(EntryPtr);
+
+ if (++(Log->Index) >= LOGSIZE)
+ {
+ Log->Index = 0;
+ }
+ //
+ // Mark next entry so we know where the log for this processor ends
+ //
+ EntryPtr = Log->Log[Log->Index];
+ sprintf(EntryPtr, "*** Last Entry");
+
+ return(pMem);
+
+}
+#endif
+
+#if DBG
+//----------------------------------------------------------------------------
+ VOID
+AcquireSpinLockDebug(
+ IN PKSPIN_LOCK pSpinLock,
+ IN PKIRQL pOldIrq,
+ IN UCHAR LockNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This function gets the spin lock, and then sets the mask in Nbtconfig, per
+ processor.
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CCHAR CurrProc;
+ UCHAR LockFree;
+
+ CTEGetLock(pSpinLock,pOldIrq);
+
+ CurrProc = (CCHAR)KeGetCurrentProcessorNumber();
+ NbtConfig.CurrProc = CurrProc;
+
+ LockFree = (LockNumber > (UCHAR)NbtConfig.CurrentLockNumber[CurrProc]);
+ if (!LockFree)
+ {
+ KdPrint(("CurrProc = %X, CurrentLockNum = %X DataSTructLock = %X\n",
+ CurrProc,NbtConfig.CurrentLockNumber[CurrProc],LockNumber));
+ } \
+
+ ASSERTMSG("Possible DeadLock, Getting SpinLock at a lower level\n",LockFree);
+ NbtConfig.CurrentLockNumber[CurrProc]|= LockNumber;
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+FreeSpinLockDebug(
+ IN PKSPIN_LOCK pSpinLock,
+ IN KIRQL OldIrq,
+ IN UCHAR LockNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This function clears the spin lock from the mask in Nbtconfig, per
+ processor and then releases the spin lock.
+
+
+Arguments:
+
+
+Return Value:
+ none
+
+--*/
+
+{
+ CCHAR CurrProc;
+
+ CurrProc = (CCHAR)KeGetCurrentProcessorNumber();
+
+ NbtConfig.CurrentLockNumber[CurrProc] &= ~LockNumber;
+ CTEFreeLock(pSpinLock,OldIrq);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+AcquireSpinLockAtDpcDebug(
+ IN PKSPIN_LOCK pSpinLock,
+ IN UCHAR LockNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This function gets the spin lock, and then sets the mask in Nbtconfig, per
+ processor.
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CCHAR CurrProc;
+ UCHAR LockFree;
+
+ CTEGetLockAtDPC(pSpinLock, 0);
+
+ CurrProc = (CCHAR)KeGetCurrentProcessorNumber();
+ NbtConfig.CurrProc = CurrProc;
+
+ LockFree = (LockNumber > (UCHAR)NbtConfig.CurrentLockNumber[CurrProc]);
+ if (!LockFree)
+ {
+ KdPrint(("CurrProc = %X, CurrentLockNum = %X DataSTructLock = %X\n",
+ CurrProc,NbtConfig.CurrentLockNumber[CurrProc],LockNumber));
+ } \
+
+ ASSERTMSG("Possible DeadLock, Getting SpinLock at a lower level\n",LockFree);
+ NbtConfig.CurrentLockNumber[CurrProc]|= LockNumber;
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+FreeSpinLockAtDpcDebug(
+ IN PKSPIN_LOCK pSpinLock,
+ IN UCHAR LockNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This function clears the spin lock from the mask in Nbtconfig, per
+ processor and then releases the spin lock.
+
+
+Arguments:
+
+
+Return Value:
+ none
+
+--*/
+
+{
+ CCHAR CurrProc;
+
+ CurrProc = (CCHAR)KeGetCurrentProcessorNumber();
+
+ NbtConfig.CurrentLockNumber[CurrProc] &= ~LockNumber;
+ CTEFreeLockFromDPC(pSpinLock, 0);
+
+}
+#endif //if Dbg
+
diff --git a/private/ntos/nbt/nt/registry.c b/private/ntos/nbt/nt/registry.c
new file mode 100644
index 000000000..6bab53a34
--- /dev/null
+++ b/private/ntos/nbt/nt/registry.c
@@ -0,0 +1,1811 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Registry.c
+
+Abstract:
+
+ This contains all routines necessary to load device pathnames from the
+ registry.
+
+Author:
+
+ Jim Stewart (Jimst) October 9 1992
+
+Revision History:
+
+
+Notes:
+
+--*/
+
+#include "nbtprocs.h"
+//#include <stdlib.h>
+
+
+//
+// Local functions used to access the registry.
+//
+
+NTSTATUS
+NbtOpenRegistry(
+ IN HANDLE NbConfigHandle,
+ IN PWSTR String,
+ OUT PHANDLE pHandle
+ );
+
+VOID
+NbtCloseRegistry(
+ IN HANDLE LinkageHandle,
+ IN HANDLE ParametersHandle
+ );
+
+NTSTATUS
+NbtReadLinkageInformation(
+ IN PWSTR pName,
+ IN HANDLE LinkageHandle,
+ OUT tDEVICES *pDevices, // place to put read in config data
+ OUT LONG *piNumDevice
+ );
+
+NTSTATUS
+OpenAndReadElement(
+ IN PUNICODE_STRING pucRootPath,
+ IN PWSTR pwsValueName,
+ OUT PUNICODE_STRING pucString
+ );
+
+ NTSTATUS
+GetServerAddress (
+ IN HANDLE ParametersHandle,
+ IN PWSTR KeyName,
+ OUT PULONG pIpAddr
+ );
+
+NTSTATUS
+NbtAppendString (
+ IN PWSTR FirstString,
+ IN PWSTR SecondString,
+ OUT PUNICODE_STRING pucString
+ );
+
+ NTSTATUS
+ReadStringRelative(
+ IN PUNICODE_STRING pRegistryPath,
+ IN PWSTR pRelativePath,
+ IN PWSTR pValueName,
+ OUT PUNICODE_STRING pOutString
+ );
+
+VOID
+NbtFindLastSlash(
+ IN PUNICODE_STRING pucRegistryPath,
+ OUT PWSTR *ppucLastElement,
+ IN int *piLength
+ );
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, NbtReadRegistry)
+#pragma CTEMakePageable(PAGE, ReadNameServerAddresses)
+#pragma CTEMakePageable(PAGE, GetServerAddress)
+#pragma CTEMakePageable(PAGE, NTReadIniString)
+#pragma CTEMakePageable(PAGE, GetIPFromRegistry)
+#pragma CTEMakePageable(PAGE, NbtOpenRegistry)
+#pragma CTEMakePageable(PAGE, NbtReadLinkageInformation)
+#pragma CTEMakePageable(PAGE, NbtReadSingleParameter)
+#pragma CTEMakePageable(PAGE, OpenAndReadElement)
+#pragma CTEMakePageable(PAGE, ReadElement)
+#pragma CTEMakePageable(PAGE, NTGetLmHostPath)
+#pragma CTEMakePageable(PAGE, ReadStringRelative)
+#pragma CTEMakePageable(PAGE, NbtFindLastSlash)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtReadRegistry(
+ IN PUNICODE_STRING RegistryPath,
+ IN PDRIVER_OBJECT DriverObject,
+ OUT tNBTCONFIG *pConfig,
+ OUT tDEVICES **ppBindDevices,
+ OUT tDEVICES **ppExportDevices,
+ OUT tADDRARRAY **ppAddrArray
+
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to get information from the registry,
+ starting at RegistryPath to get the parameters.
+
+Arguments:
+
+ RegistryPath - Supplies RegistryPath. The name of Nbt's node in the
+ registry.
+
+ pNbtConfig - ptr to global configuration strucuture for NBT
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+ PWSTR BindName = NBT_BIND;
+ PWSTR ExportName = NBT_EXPORT;
+ PWSTR pwsNameServer = NBT_MAINNAME_SERVICE;
+ PWSTR pwsBackupNameServer = NBT_BACKUP_SERVER;
+ PWSTR pwsParmsKeyName = NBT_PARAMETERS;
+ NTSTATUS OpenStatus;
+ HANDLE LinkageHandle;
+ HANDLE ParametersHandle;
+ HANDLE NbtConfigHandle;
+ NTSTATUS Status;
+ ULONG Disposition;
+ OBJECT_ATTRIBUTES TmpObjectAttributes;
+ PWSTR LinkageString = L"Linkage";
+ PWSTR ParametersString = L"Parameters";
+ tDEVICES *pBindDevices;
+ tDEVICES *pExportDevices;
+ UNICODE_STRING ucString;
+
+ CTEPagedCode();
+
+ *ppExportDevices = *ppBindDevices = NULL;
+ *ppAddrArray = NULL;
+
+ // this procedure can be called from the DHCP activated code. In
+ // that case we just want to read the registry and not Zero the
+ // NbtConfig data structure.
+ if (DriverObject)
+ {
+ //
+ // Initialize the Configuration data structure
+ //
+ CTEZeroMemory(pConfig,sizeof(tNBTCONFIG));
+ NbtConfig.TransactionId = WINS_MAXIMUM_TRANSACTION_ID + 1;
+
+ // save the driver object for event logging purposes
+ //
+ NbtConfig.DriverObject = DriverObject;
+
+ // save the registry path for later use when DHCP asks us
+ // to re-read the registry.
+ //
+ NbtConfig.pRegistry.Buffer = NbtAllocMem(RegistryPath->MaximumLength,NBT_TAG('i'));
+ NbtConfig.pRegistry.MaximumLength = (USHORT)RegistryPath->MaximumLength;
+ if (NbtConfig.pRegistry.Buffer)
+ {
+ RtlCopyUnicodeString(&NbtConfig.pRegistry,RegistryPath);
+ }
+ else
+ return(STATUS_INSUFFICIENT_RESOURCES);
+
+ // clear the ptr to the broadcast netbios name. This ptr is an optimization
+ // that lets us resolve broadcast netbios name quickly
+ pConfig->pBcastNetbiosName = NULL;
+ }
+ //
+ // Open the registry.
+ //
+
+ InitializeObjectAttributes(
+ &TmpObjectAttributes,
+ RegistryPath, // name
+ OBJ_CASE_INSENSITIVE, // attributes
+ NULL, // root
+ NULL // security descriptor
+ );
+
+ Status = ZwCreateKey(
+ &NbtConfigHandle,
+ KEY_WRITE,
+ &TmpObjectAttributes,
+ 0, // title index
+ NULL, // class
+ 0, // create options
+ &Disposition); // disposition
+
+ if (!NT_SUCCESS(Status))
+ {
+ NbtLogEvent(EVENT_NBT_CREATE_DRIVER,Status);
+
+ return STATUS_UNSUCCESSFUL;
+ }
+
+
+ OpenStatus = NbtOpenRegistry(
+ NbtConfigHandle,
+ LinkageString,
+ &LinkageHandle);
+
+ if (NT_SUCCESS(OpenStatus))
+ {
+ OpenStatus = NbtOpenRegistry(
+ NbtConfigHandle,
+ ParametersString,
+ &ParametersHandle);
+
+ if (NT_SUCCESS(OpenStatus))
+ {
+ //
+ // Read in the binding information (if none is present
+ // the array will be filled with all known drivers).
+ //
+ pBindDevices = NbtAllocMem(sizeof(tDEVICES),NBT_TAG('i'));
+
+ if (pBindDevices)
+ {
+ pExportDevices = NbtAllocMem(sizeof(tDEVICES),NBT_TAG('i'));
+ if (pExportDevices)
+ {
+ ULONG NumDevices;
+
+ //
+ // Read various parameters from the registry
+ //
+ ReadParameters(pConfig,ParametersHandle);
+
+ Status = NbtReadLinkageInformation (
+ BindName,
+ LinkageHandle,
+ pBindDevices,
+ (PLONG)&pConfig->uNumDevices);
+
+ if ( Status == STATUS_ILL_FORMED_SERVICE_ENTRY )
+ {
+ CTEMemFree(pBindDevices);
+ CTEMemFree(pExportDevices);
+ pBindDevices = pExportDevices = NULL;
+ pConfig->uNumDevices = 0;
+ }
+ else
+ {
+ if (!NT_SUCCESS(Status))
+ {
+ NbtLogEvent(EVENT_NBT_READ_BIND,Status);
+ return(Status);
+ }
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Binddevice = %ws\n",pBindDevices->Names[0].Buffer));
+
+ // Read the EXPORT information as well.
+ Status = NbtReadLinkageInformation (
+ ExportName,
+ LinkageHandle,
+ pExportDevices,
+ &NumDevices);
+
+ // we want the lowest number for num devices in case there
+ // are more bindings than exports or viceversa
+ //
+ pConfig->uNumDevices = (USHORT)( pConfig->uNumDevices > NumDevices ?
+ NumDevices : pConfig->uNumDevices);
+
+ if (!NT_SUCCESS(Status) || (pConfig->uNumDevices == 0))
+ {
+ NbtLogEvent(EVENT_NBT_READ_EXPORT,Status);
+ if (NT_SUCCESS(Status))
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ return(Status);
+ }
+
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Exportdevice = %ws\n",pExportDevices->Names[0].Buffer));
+
+ //
+ // read in the NameServer IP address now
+ //
+ Status = ReadNameServerAddresses(NbtConfigHandle,
+ pBindDevices,
+ pConfig->uNumDevices,
+ ppAddrArray);
+
+ if (!NT_SUCCESS(Status))
+ {
+ if (!(NodeType & BNODE))
+ {
+ NbtLogEvent(EVENT_NBT_NAME_SERVER_ADDRS,Status);
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Nbt: Failed to Read the name Server Addresses!!, status = %X\n",
+ Status));
+ }
+ //
+ // we don't fail startup if we can't read the name
+ // server addresses
+ //
+ Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ //
+ // check if any WINS servers have been configured change
+ // to Hnode
+ //
+ if (NodeType & (BNODE | DEFAULT_NODE_TYPE))
+ {
+ ULONG i;
+ for (i=0;i<pConfig->uNumDevices ;i++ )
+ {
+ if (((*ppAddrArray)[i].NameServerAddress != LOOP_BACK) ||
+ ((*ppAddrArray)[i].BackupServer != LOOP_BACK))
+ {
+ NodeType = MSNODE | (NodeType & PROXY);
+ break;
+ }
+ }
+ }
+ }
+ }
+ //
+ // we have done the check for default node so turn off
+ // the flag
+ //
+ NodeType &= ~DEFAULT_NODE_TYPE;
+ //
+ // A Bnode cannot be a proxy too
+ //
+ if (NodeType & BNODE)
+ {
+ if (NodeType & PROXY)
+ {
+ NodeType &= ~PROXY;
+ }
+ }
+
+ // keep the size around for allocating memory, so that when we run over
+ // OSI, only this value should change (in theory at least)
+ pConfig->SizeTransportAddress = sizeof(TDI_ADDRESS_IP);
+
+ // fill in the node type value that is put into all name service Pdus
+ // that go out identifying this node type
+ switch (NodeType & NODE_MASK)
+ {
+ case BNODE:
+ pConfig->PduNodeType = 0;
+ break;
+ case PNODE:
+ pConfig->PduNodeType = 1 << 13;
+ break;
+ case MNODE:
+ pConfig->PduNodeType = 1 << 14;
+ break;
+ case MSNODE:
+ pConfig->PduNodeType = 3 << 13;
+ break;
+
+ }
+
+ // read the name of the transport to bind to
+ //
+ Status = ReadElement(ParametersHandle,
+ WS_TRANSPORT_BIND_NAME,
+ &ucString);
+ if (!NT_SUCCESS(Status))
+ {
+ NbtConfig.pTcpBindName = NBT_TCP_BIND_NAME;
+ Status = STATUS_SUCCESS;
+ StreamsStack = TRUE;
+ }
+ else
+ {
+ UNICODE_STRING StreamsString;
+
+ //
+ // if there is already a bind string, free it before
+ // allocating another
+ //
+ if (NbtConfig.pTcpBindName)
+ {
+ CTEMemFree(NbtConfig.pTcpBindName);
+ }
+ NbtConfig.pTcpBindName = ucString.Buffer;
+
+ // ********** REMOVE LATER ***********
+ RtlInitUnicodeString(&StreamsString,NBT_TCP_BIND_NAME);
+ if (RtlCompareUnicodeString(&ucString,&StreamsString,FALSE))
+ StreamsStack = FALSE;
+ else
+ StreamsStack = TRUE;
+
+ }
+ ZwClose(LinkageHandle);
+ ZwClose (NbtConfigHandle);
+ ZwClose(ParametersHandle);
+
+ *ppExportDevices = pExportDevices;
+ *ppBindDevices = pBindDevices;
+ return(Status);
+ }
+
+ CTEMemFree(pBindDevices);
+
+ }
+ ZwClose(ParametersHandle);
+ }
+ else
+ NbtLogEvent(EVENT_NBT_OPEN_REG_PARAMS,OpenStatus);
+
+ ZwClose(LinkageHandle);
+ }
+
+ ZwClose (NbtConfigHandle);
+
+ NbtLogEvent(EVENT_NBT_OPEN_REG_LINKAGE,OpenStatus);
+
+ return STATUS_UNSUCCESSFUL;
+
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+ReadNameServerAddresses (
+ IN HANDLE NbtConfigHandle,
+ IN tDEVICES *BindDevices,
+ IN ULONG NumberDevices,
+ OUT tADDRARRAY **ppAddrArray
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to read the name server addresses from the registry.
+ It stores them in a data structure that it allocates. This memory is
+ subsequently freed in driver.c when the devices have been created.
+
+Arguments:
+
+ ConfigurationInfo - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#define ADAPTER_SIZE_MAX 200
+
+ UNICODE_STRING ucString;
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+ HANDLE Handle;
+ LONG i,j,Len;
+ PWSTR pwsNameServer = L"NameServer";
+ PWSTR pwsDhcpNameServer = L"DhcpNameServer";
+ PWSTR pwsBackup = L"NameServerBackup";
+ PWSTR pwsDhcpBackup = L"DhcpNameServerBackup";
+ PWSTR pwsAdapter = L"Adapters\\";
+ PWSTR BackSlash = L"\\";
+ tADDRARRAY *pAddrArray;
+ ULONG LenAdapter;
+
+ CTEPagedCode();
+
+
+ // this is large enough for 100 characters of adapter name.
+ ucString.Buffer = NbtAllocMem(ADAPTER_SIZE_MAX,NBT_TAG('i'));
+
+ *ppAddrArray = NULL;
+ if (!ucString.Buffer)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pAddrArray = NbtAllocMem(sizeof(tADDRARRAY)*NumberDevices,NBT_TAG('i'));
+ CTEZeroMemory(pAddrArray,sizeof(tADDRARRAY)*NumberDevices);
+
+ if (!pAddrArray)
+ {
+ CTEMemFree(ucString.Buffer);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ *ppAddrArray = pAddrArray;
+
+ // get the adapter name out of the Bind string, and use it to open
+ // a key by the same name, to get the name server addresses
+ //
+ for (i = 0;i < (LONG)NumberDevices ;i ++ )
+ {
+ WCHAR *pBuffer;
+
+ Len = BindDevices->Names[i].Length/sizeof(WCHAR);
+ Len--;
+ //
+ // start at the end a work backwards looking for a '\'
+ //
+ j = Len;
+ pBuffer = &BindDevices->Names[i].Buffer[j];
+ while (j)
+ {
+ if (*pBuffer != *BackSlash)
+ {
+ j--;
+ pBuffer--;
+ }
+ else
+ break;
+ }
+
+ // if we don't find a backslash or at least one
+ // character name then continue around again, or the name
+ // is longer than the buffer, then go to the next device in the
+ // bind list
+ //
+ if ((j == 0) ||
+ (j == Len) ||
+ (j == Len -1) ||
+ ((Len - j) > ADAPTER_SIZE_MAX))
+ {
+ continue;
+ }
+
+ // copy the string "Adapter\" to the buffer since the adapters all
+ // appear under this key in the registery
+ //
+
+ LenAdapter = wcslen(pwsAdapter);
+ CTEMemCopy(ucString.Buffer,
+ pwsAdapter,
+ LenAdapter*sizeof(WCHAR));
+ // copy just the adapter name from the Bind string, since that is
+ // the name of the key to open to find the name server ip addresses
+ //
+ CTEMemCopy(&ucString.Buffer[LenAdapter],
+ ++pBuffer,
+ (Len - j)*sizeof(WCHAR));
+
+ ucString.Buffer[Len - j + LenAdapter] = 0;
+
+ status = NbtOpenRegistry(
+ NbtConfigHandle,
+ ucString.Buffer,
+ &Handle);
+
+ pAddrArray->NameServerAddress = LOOP_BACK;
+ pAddrArray->BackupServer = LOOP_BACK;
+
+ if (NT_SUCCESS(status))
+ {
+ status = GetServerAddress(Handle,
+ pwsNameServer,
+ &pAddrArray->NameServerAddress);
+ //
+ // If there is no WINS addres in the registry or the address is
+ // null, which we map to Loop_Back, then try the Dhcp keys to see
+ // if Dhcp has written a value.
+ //
+ if (!NT_SUCCESS(status) ||
+ (pAddrArray->NameServerAddress == LOOP_BACK))
+ {
+ status = GetServerAddress(Handle,
+ pwsDhcpNameServer,
+ &pAddrArray->NameServerAddress);
+
+ status = GetServerAddress(Handle,
+ pwsDhcpBackup,
+ &pAddrArray->BackupServer);
+ }
+ else
+ {
+ status = GetServerAddress(Handle,
+ pwsBackup,
+ &pAddrArray->BackupServer);
+
+ }
+
+ // don't want to fail this routine just because the
+ // name server address was not set
+ status = STATUS_SUCCESS;
+
+ ZwClose(Handle);
+ }
+ pAddrArray++;
+
+ }
+
+ CTEMemFree(ucString.Buffer);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+GetServerAddress (
+ IN HANDLE ParametersHandle,
+ IN PWSTR KeyName,
+ OUT PULONG pIpAddr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to read the name server addresses from the registry.
+
+Arguments:
+
+ ConfigurationInfo - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS status;
+ ULONG IpAddr;
+ PUCHAR NameServer;
+
+ CTEPagedCode();
+
+ status = CTEReadIniString(ParametersHandle,KeyName,&NameServer);
+
+ if (NT_SUCCESS(status))
+ {
+ status = ConvertDottedDecimalToUlong(NameServer,&IpAddr);
+ if (NT_SUCCESS(status) && IpAddr)
+ {
+ *pIpAddr = IpAddr;
+ }
+ else
+ {
+ if (IpAddr != 0)
+ {
+ NbtLogEvent(EVENT_NBT_BAD_PRIMARY_WINS_ADDR,0);
+ }
+ *pIpAddr = LOOP_BACK;
+ }
+
+ CTEMemFree((PVOID)NameServer);
+
+
+ }
+ else
+ {
+ *pIpAddr = LOOP_BACK;
+ }
+
+ return(status);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtAppendString (
+ IN PWSTR FirstString,
+ IN PWSTR SecondString,
+ OUT PUNICODE_STRING pucString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to append the second string to the first string.
+ It allocates memory for this, so the caller must be sure to free it.
+
+Arguments:
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
+ ULONG Length;
+ PWSTR pDhcpKeyName;
+
+ CTEPagedCode();
+
+ Length = (wcslen(FirstString) + wcslen(SecondString) + 1)*sizeof(WCHAR);
+ pDhcpKeyName = NbtAllocMem(Length,NBT_TAG('i'));
+ if (pDhcpKeyName)
+ {
+ pucString->Buffer = pDhcpKeyName;
+ pucString->Length = (USHORT)0;
+ pucString->MaximumLength = (USHORT)Length;
+ pucString->Buffer[0] = UNICODE_NULL;
+
+ status = RtlAppendUnicodeToString(pucString,FirstString);
+ if (NT_SUCCESS(status))
+ {
+ status = RtlAppendUnicodeToString(pucString,SecondString);
+ if (NT_SUCCESS(status))
+ {
+ return status;
+ }
+ }
+ CTEFreeMem(pDhcpKeyName);
+
+ }
+ return(status);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTReadIniString (
+ IN HANDLE ParametersHandle,
+ IN PWSTR KeyName,
+ OUT PUCHAR *ppString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to read a string of configuration information from
+ the registry.
+
+Arguments:
+
+ ParametersHandle - handle to open key in registry
+ KeyName - key to read
+ ppString - returned string
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UNICODE_STRING ucString;
+ STRING String;
+ NTSTATUS status;
+ PUCHAR pBuffer;
+ PWSTR Dhcp = L"Dhcp";
+
+ CTEPagedCode();
+ //
+ // read in the Scope Id
+ //
+ status = ReadElement(
+ ParametersHandle,
+ KeyName, // Value to read
+ &ucString); // return value
+
+ //
+ // if the key is not there or it is set to a null string try to read the
+ // dhcp key
+ //
+ if (!NT_SUCCESS(status) || (ucString.Length == 0))
+ {
+ UNICODE_STRING String;
+
+ // free the string allocated in ReadElement
+ if (NT_SUCCESS(status))
+ {
+ CTEMemFree(ucString.Buffer);
+ }
+ //
+ // try to read a similar string that is prefixed with "DHCP"
+ // incase there is only the DHCP configuration information present
+ // and not overrides keys.
+ //
+ status = NbtAppendString(Dhcp,KeyName,&String);
+ if (NT_SUCCESS(status))
+ {
+ status = ReadElement(
+ ParametersHandle,
+ String.Buffer, // Value to read
+ &ucString); // return value
+
+ // free the buffer allocated in NbtAppendString
+ CTEFreeMem(String.Buffer);
+ }
+ }
+ // the scope must be less than
+ // 255-16 characters since the whole name is limited to 255 as per the
+ // RFC
+ //
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Nbt: ReadIniString = %ws\n",ucString.Buffer));
+
+ if (NT_SUCCESS(status))
+ {
+ if ((ucString.Length > 0) &&
+ (ucString.Length <= (255 - NETBIOS_NAME_SIZE)*sizeof(WCHAR)))
+ {
+
+ pBuffer = NbtAllocMem(ucString.MaximumLength/sizeof(WCHAR),NBT_TAG('i'));
+
+ if (pBuffer)
+ {
+ // convert to an ascii string and store in the config data structure
+ // increment pBuffer to leave room for the length byte
+ //
+ String.Buffer = pBuffer;
+ String.MaximumLength = ucString.MaximumLength/sizeof(WCHAR);
+ status = RtlUnicodeStringToAnsiString(&String,
+ &ucString,
+ FALSE);
+
+ if (NT_SUCCESS(status))
+ {
+ *ppString = pBuffer;
+ }
+ else
+ {
+ CTEMemFree(pBuffer);
+ }
+ }
+ else
+ status = STATUS_UNSUCCESSFUL;
+
+
+ }
+ else
+ if (NT_SUCCESS(status))
+ {
+ // force the code to setup a null scope since the one in the
+ // registry is null
+ //
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ // free the string allocated in ReadElement
+ CTEMemFree(ucString.Buffer);
+ }
+
+
+ return(status);
+}
+
+ VOID
+NbtFreeRegistryInfo (
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Nbt to free any storage that was allocated
+ by NbConfigureTransport in producing the specified CONFIG_DATA structure.
+
+Arguments:
+
+ ConfigurationInfo - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+GetIPFromRegistry(
+ IN PUNICODE_STRING pucRegistryPath,
+ IN PUNICODE_STRING pucBindDevice,
+ OUT PULONG pulIpAddress,
+ OUT PULONG pulSubnetMask,
+ IN BOOL fWantDhcpAddresses
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to get the IP address of an adapter from the
+ Registry. The Registry path variable contains the path name
+ for NBT's registry entries. The last element of this path name is
+ removed to give the path to any card in the registry.
+
+ The BindDevice path contains a Bind string for NBT. We remove the last
+ element of this path (which is the adapter name \Elnkii01) and tack it
+ onto the modified registry path from above. We then tack on
+ \Parameters which will give the full path to the Tcpip key, which
+ we open to get the Ip address.
+
+
+Arguments:
+
+ pucRegistryPath - Supplies pucRegistryPath. The name of Nbt's node in the
+ registry.
+
+ pNbtConfig - ptr to global configuration strucuture for NBT
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+ PWSTR pwsIpAddressName = ( fWantDhcpAddresses ? L"DhcpIPAddress" : L"IPAddress" ); // value name to read
+ PWSTR pwsSubnetMask = ( fWantDhcpAddresses ? L"DhcpSubnetMask" : L"SubnetMask" ); // value name to read
+ PWSTR TcpParams = L"\\Parameters\\Tcpip"; // key to open
+ ULONG Len;
+ ULONG iBindPathLength;
+ PVOID pBuffer;
+ NTSTATUS Status;
+ PWSTR pwsString;
+ UNICODE_STRING Path;
+ UNICODE_STRING ucIpAddress;
+ UNICODE_STRING ucSubnetMask;
+
+
+ CTEPagedCode();
+
+ // now find the last back slash in the path name to the bind device
+ NbtFindLastSlash(pucBindDevice,&pwsString,&iBindPathLength);
+ if (pwsString)
+ {
+ // get the length of the adapter name (+1 for unicode null)
+ //
+ Len = (wcslen(pwsString) + wcslen(TcpParams) + 1) * sizeof(WCHAR);
+ pBuffer = NbtAllocMem(Len,NBT_TAG('i'));
+ if (!pBuffer)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ Path.Buffer = pBuffer;
+ Path.MaximumLength = (USHORT)Len;
+ Path.Length = 0;
+
+ // put adapter name in the Path string
+ Status = RtlAppendUnicodeToString(&Path,pwsString);
+
+ if (NT_SUCCESS(Status))
+ {
+ // put Tcpip\parameters on the end of the adapter name
+ Status = RtlAppendUnicodeToString(&Path,TcpParams);
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = ReadStringRelative(&NbtConfig.pRegistry,
+ Path.Buffer,
+ pwsIpAddressName,
+ &ucIpAddress);
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = ConvertToUlong(&ucIpAddress,pulIpAddress);
+
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Convert Ipaddr string= %ws,ulong = %X\n",ucIpAddress.Buffer,*pulIpAddress));
+
+ // free the unicode string buffers allocated when the data was read
+ // from the registry
+ //
+ CTEMemFree(ucIpAddress.Buffer);
+
+ //
+ // DHCP may put a 0 Ip address in the registry - we don't want to
+ // boot netbt under these conditions.
+ //
+ if (*pulIpAddress == 0)
+ {
+ Status = STATUS_INVALID_ADDRESS;
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ // read the broadcast address in now
+ Status = ReadStringRelative(&NbtConfig.pRegistry,
+ Path.Buffer,
+ pwsSubnetMask,
+ &ucSubnetMask);
+
+ if (NT_SUCCESS(Status))
+ {
+ // we must convert the Subnet mask to a broadcast address...
+ Status = ConvertToUlong(&ucSubnetMask,pulSubnetMask);
+ if (!NT_SUCCESS(Status))
+ {
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Unable to convert dotted decimal SubnetMask to ULONG string= %ws\n",
+ ucIpAddress.Buffer));
+
+ Status = STATUS_INVALID_ADDRESS;
+ }
+
+ CTEMemFree(ucSubnetMask.Buffer);
+ }
+ else
+ {
+ Status = STATUS_INVALID_ADDRESS;
+ }
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("Unable to convert dotted decimal IpAddress to ULONG string= %ws\n",
+ ucIpAddress.Buffer));
+
+ Status = STATUS_INVALID_ADDRESS;
+ }
+
+ }
+ }
+
+
+ }
+ //
+ // free the string with the path to the adapter in it
+ //
+ CTEMemFree(pBuffer);
+ }
+ else
+ Status = STATUS_UNSUCCESSFUL;
+
+ return Status;
+
+} // GetIPFromRegistry
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtOpenRegistry(
+ IN HANDLE NbConfigHandle,
+ IN PWSTR String,
+ OUT PHANDLE pHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Nbt to open the registry. If the registry
+ tree for Nbt exists, then it opens it and returns TRUE. If not, it
+ creates the appropriate keys in the registry, opens it, and
+ returns FALSE.
+
+
+Arguments:
+
+ NbConfigHandle - this is the root handle which String is relative to
+ String - the name of the key to open below the root handle
+ pHandle - returns the handle to the String key.
+
+Return Value:
+
+ The status of the request.
+
+--*/
+{
+
+ NTSTATUS Status;
+ UNICODE_STRING KeyName;
+ OBJECT_ATTRIBUTES TmpObjectAttributes;
+
+ CTEPagedCode();
+ //
+ // Open the Nbt key.
+ //
+
+ RtlInitUnicodeString (&KeyName, String);
+
+ InitializeObjectAttributes(
+ &TmpObjectAttributes,
+ &KeyName, // name
+ OBJ_CASE_INSENSITIVE, // attributes
+ NbConfigHandle, // root
+ NULL // security descriptor
+ );
+
+ Status = ZwOpenKey(
+ pHandle,
+ KEY_READ,
+ &TmpObjectAttributes);
+
+
+ return Status;
+
+} /* NbOpenRegistry */
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtReadLinkageInformation(
+ IN PWSTR pName,
+ IN HANDLE LinkageHandle,
+ OUT tDEVICES *pDevices, // place to put read in config data
+ OUT LONG *pNumDevices
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Nbt to read its linkage information
+ from the registry. If there is none present, then ConfigData
+ is filled with a list of all the adapters that are known
+ to Nbt.
+
+Arguments:
+
+ RegistryHandle - A pointer to the open registry.
+
+Return Value:
+
+ Status
+
+--*/
+
+{
+ UNICODE_STRING BindString;
+ NTSTATUS RegistryStatus;
+
+ PKEY_VALUE_FULL_INFORMATION BindValue;
+ ULONG BytesWritten;
+ USHORT ConfigBindings = 0;
+ PWSTR CurBindValue;
+ ULONG Count;
+ PVOID pBuffer;
+
+
+ CTEPagedCode();
+ //
+ // We read the parameters out of the registry
+ // linkage key.
+ //
+ RegistryStatus = STATUS_BUFFER_OVERFLOW;
+ Count = 1;
+ while ((RegistryStatus == STATUS_BUFFER_OVERFLOW) && (Count < 20))
+ {
+ pBuffer = NbtAllocMem(REGISTRY_BUFF_SIZE*Count,NBT_TAG('i'));
+ if (!pBuffer)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ BindValue = (PKEY_VALUE_FULL_INFORMATION)pBuffer;
+
+ // copy "Bind" or "Export" into the unicode string
+ RtlInitUnicodeString (&BindString, pName);
+
+ RegistryStatus = ZwQueryValueKey(
+ LinkageHandle,
+ &BindString, // string to retrieve
+ KeyValueFullInformation,
+ (PVOID)BindValue, // returned info
+ REGISTRY_BUFF_SIZE*Count,
+ &BytesWritten // # of bytes returned
+ );
+ Count++;
+ if (RegistryStatus == STATUS_BUFFER_OVERFLOW)
+ {
+ CTEMemFree(pBuffer);
+ }
+ }
+
+ if (!NT_SUCCESS(RegistryStatus) ||
+ (RegistryStatus == STATUS_BUFFER_OVERFLOW))
+ {
+ CTEMemFree(pBuffer);
+ return RegistryStatus;
+ }
+
+ if ( BytesWritten == 0 )
+ {
+ CTEMemFree(pBuffer);
+ return STATUS_ILL_FORMED_SERVICE_ENTRY;
+ }
+
+
+ // allocate memory for the unicode strings, currently in BindValue
+ // on the stack
+ pDevices->RegistrySpace = (PVOID)NbtAllocMem((USHORT)BytesWritten,NBT_TAG('i'));
+
+ if ( pDevices->RegistrySpace == NULL )
+ {
+ CTEMemFree(pBuffer);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlMoveMemory((PVOID)pDevices->RegistrySpace, (PVOID)BindValue, BytesWritten);
+
+ // Point to the permanent location for the strings
+ BindValue = (PKEY_VALUE_FULL_INFORMATION)pDevices->RegistrySpace;
+
+ CurBindValue = (PWCHAR)((PUCHAR)BindValue + BindValue->DataOffset);
+
+ while ((*CurBindValue != 0) &&
+ (ConfigBindings < NBT_MAXIMUM_BINDINGS))
+ {
+
+ // this sets the buffer ptr in Names to point to CurBindValue, so
+ // this value must be real memory and not stack, hence the need
+ // to allocate memory above...
+ RtlInitUnicodeString (&pDevices->Names[ConfigBindings],
+ (PCWSTR)CurBindValue);
+
+ ++ConfigBindings;
+
+ //
+ // Now advance the "Bind" value.
+ //
+
+ // wcslen => wide character string length for a unicode string
+ CurBindValue += wcslen((PCWSTR)CurBindValue) + 1;
+
+ }
+ *pNumDevices = ConfigBindings;
+
+ CTEMemFree(pBuffer);
+ return STATUS_SUCCESS;
+
+} /* NbtReadLinkageInformation */
+
+//----------------------------------------------------------------------------
+ ULONG
+NbtReadSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG DefaultValue,
+ IN ULONG MinimumValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Nbt to read a single parameter
+ from the registry. If the parameter is found it is stored
+ in Data.
+
+Arguments:
+
+ ParametersHandle - A pointer to the open registry.
+
+ ValueName - The name of the value to search for.
+
+ DefaultValue - The default value.
+
+Return Value:
+
+ The value to use; will be the default if the value is not
+ found or is not in the correct range.
+
+--*/
+
+{
+ static ULONG InformationBuffer[60];
+ PKEY_VALUE_FULL_INFORMATION Information =
+ (PKEY_VALUE_FULL_INFORMATION)InformationBuffer;
+ UNICODE_STRING ValueKeyName;
+ ULONG InformationLength;
+ ULONG ReturnValue=DefaultValue;
+ NTSTATUS Status;
+ ULONG Count=2;
+ PWSTR Dhcp = L"Dhcp";
+ BOOLEAN FreeString = FALSE;
+
+ CTEPagedCode();
+ RtlInitUnicodeString (&ValueKeyName, ValueName);
+
+ while (Count--)
+ {
+
+ Status = ZwQueryValueKey(
+ ParametersHandle,
+ &ValueKeyName,
+ KeyValueFullInformation,
+ (PVOID)Information,
+ sizeof (InformationBuffer),
+ &InformationLength);
+
+
+ if ((Status == STATUS_SUCCESS) && (Information->DataLength == sizeof(ULONG)))
+ {
+
+ RtlMoveMemory(
+ (PVOID)&ReturnValue,
+ ((PUCHAR)Information) + Information->DataOffset,
+ sizeof(ULONG));
+
+ if (ReturnValue < MinimumValue)
+ {
+ ReturnValue = MinimumValue;
+ }
+
+ }
+ else
+ {
+ //
+ // try to read the Dhcp key instead if the first read failed.
+ //
+ Status = STATUS_SUCCESS;
+ if (Count)
+ {
+ Status = NbtAppendString(Dhcp,ValueName,&ValueKeyName);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ Count = 0;
+ ReturnValue = DefaultValue;
+ }
+ else
+ FreeString = TRUE;
+
+
+ }
+ } // of while
+
+ // nbt append string allocates memory.
+ if (FreeString)
+ {
+ CTEMemFree(ValueKeyName.Buffer);
+
+ }
+ return ReturnValue;
+
+} /* NbtReadSingleParameter */
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+OpenAndReadElement(
+ IN PUNICODE_STRING pucRootPath,
+ IN PWSTR pwsValueName,
+ OUT PUNICODE_STRING pucString
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by Nbt to read in the Ip address appearing in the
+ registry at the path pucRootPath, with a key of pwsKeyName
+
+Arguments:
+ pucRootPath - the registry path to the key to read
+ pwsKeyName - the key to open (i.e. Tcpip)
+ pwsValueName- the name of the value to read (i.e. IPAddress)
+
+Return Value:
+
+ pucString - the string returns the string read from the registry
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ HANDLE hRootKey;
+ OBJECT_ATTRIBUTES TmpObjectAttributes;
+
+ CTEPagedCode();
+
+ InitializeObjectAttributes(
+ &TmpObjectAttributes,
+ pucRootPath, // name
+ OBJ_CASE_INSENSITIVE, // attributes
+ NULL, // root
+ NULL // security descriptor
+ );
+
+ Status = ZwOpenKey(
+ &hRootKey,
+ KEY_READ,
+ &TmpObjectAttributes);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ Status = ReadElement(hRootKey,pwsValueName,pucString);
+
+ ZwClose (hRootKey);
+ return(Status);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+ReadElement(
+ IN HANDLE HandleToKey,
+ IN PWSTR pwsValueName,
+ OUT PUNICODE_STRING pucString
+ )
+/*++
+
+Routine Description:
+
+ This routine is will read a string value given by pwsValueName, under a
+ given Key (which must be open) - given by HandleToKey. This routine
+ allocates memory for the buffer in the returned pucString, so the caller
+ must deallocate that.
+
+Arguments:
+
+ pwsValueName- the name of the value to read (i.e. IPAddress)
+
+Return Value:
+
+ pucString - the string returns the string read from the registry
+
+--*/
+
+{
+ ULONG ReadStorage[150]; // 600 bytes
+ ULONG BytesRead;
+ NTSTATUS Status;
+ PWSTR pwsSrcString;
+ PKEY_VALUE_FULL_INFORMATION ReadValue =
+ (PKEY_VALUE_FULL_INFORMATION)ReadStorage;
+
+ CTEPagedCode();
+
+ // now put the name of the value to read into a unicode string
+ RtlInitUnicodeString(pucString,pwsValueName);
+
+ // this read the value of IPAddress under the key opened above
+ Status = ZwQueryValueKey(
+ HandleToKey,
+ pucString, // string to retrieve
+ KeyValueFullInformation,
+ (PVOID)ReadValue, // returned info
+ sizeof(ReadStorage),
+ &BytesRead // # of bytes returned
+ );
+
+ if ( Status == STATUS_BUFFER_OVERFLOW )
+ {
+ ReadValue = (PKEY_VALUE_FULL_INFORMATION) NbtAllocMem( BytesRead, NBT_TAG('i'));
+ if ( ReadValue == NULL )
+ {
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("ReadElement: failed to allocate %d bytes for element\n",BytesRead));
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto ReadElement_Return;
+ }
+ Status = ZwQueryValueKey(
+ HandleToKey,
+ pucString, // string to retrieve
+ KeyValueFullInformation,
+ (PVOID)ReadValue, // returned info
+ BytesRead,
+ &BytesRead // # of bytes returned
+ );
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ IF_DBG(NBT_DEBUG_NTUTIL)
+ KdPrint(("failed to Query Value Status = %X\n",Status));
+ goto ReadElement_Return;
+ }
+
+ if ( BytesRead == 0 )
+ {
+ Status = STATUS_ILL_FORMED_SERVICE_ENTRY;
+ goto ReadElement_Return;
+ }
+ else
+ if (ReadValue->DataLength == 0)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ goto ReadElement_Return;
+ }
+
+
+ // create the pucString and copy the data returned to it
+ // assumes that the ReadValue string ends in a UNICODE_NULL
+ //bStatus = RtlCreateUnicodeString(pucString,pwSrcString);
+ pwsSrcString = (PWSTR)NbtAllocMem((USHORT)ReadValue->DataLength,NBT_TAG('i'));
+ if (!pwsSrcString)
+ {
+ ASSERTMSG((PVOID)pwsSrcString,
+ (PCHAR)"Unable to allocate memory for a Unicode string");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ // move the read in data from the stack to the memory allocated
+ // from the nonpaged pool
+ RtlMoveMemory(
+ (PVOID)pwsSrcString,
+ ((PUCHAR)ReadValue) + ReadValue->DataOffset,
+ ReadValue->DataLength);
+
+ RtlInitUnicodeString(pucString,pwsSrcString);
+ // if there isn't a null on the end of the pwsSrcString, then
+ // it will not work correctly. - a null string comes out with a
+ // length of 1!! since the null is counted therefore use
+ // rtlinitunicode string afterall.
+ // pucString->MaximumLength = ReadValue->DataLength;
+ // pucString->Length = ReadValue->DataLength;
+ // pucString->Buffer = pwsSrcString;
+ }
+
+ReadElement_Return:
+
+ if ( ( ReadValue != (PKEY_VALUE_FULL_INFORMATION)ReadStorage )
+ && ( ReadValue != NULL ) )
+ {
+ CTEFreeMem(ReadValue);
+ }
+ return(Status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTGetLmHostPath(
+ OUT PUCHAR *ppPath
+ )
+/*++
+
+Routine Description:
+
+ This routine will read the DataBasePath from under
+ ...\tcpip\parameters\databasepath
+
+Arguments:
+
+ pPath - ptr to a buffer containing the path name.
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ UNICODE_STRING ucDataBase;
+ STRING StringPath;
+ STRING LmhostsString;
+ ULONG StringMax;
+ PWSTR LmHosts = L"lmhosts";
+ PWSTR TcpIpParams = L"TcpIp\\Parameters";
+ PWSTR TcpParams = L"Tcp\\Parameters";
+ PWSTR DataBase = L"DataBasePath";
+ PCHAR ascLmhosts="\\lmhosts";
+ PCHAR pBuffer;
+
+ CTEPagedCode();
+
+ status = ReadStringRelative(&NbtConfig.pRegistry,
+ TcpIpParams,
+ DataBase,
+ &ucDataBase);
+
+ if (!NT_SUCCESS(status))
+ {
+ // check for the new TCP stack which a slightly different registry
+ // key name.
+ //
+ status = ReadStringRelative(&NbtConfig.pRegistry,
+ TcpParams,
+ DataBase,
+ &ucDataBase);
+ if (!NT_SUCCESS(status))
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+
+ StringMax = ucDataBase.Length/sizeof(WCHAR) + strlen(ascLmhosts) + 1;
+ pBuffer = NbtAllocMem(StringMax,NBT_TAG('i'));
+ if (!pBuffer)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ StringPath.Buffer = (PCHAR)pBuffer;
+ StringPath.MaximumLength = (USHORT)StringMax;
+ StringPath.Length = (USHORT)StringMax;
+
+ // convert to ascii from unicode
+ status = RtlUnicodeStringToAnsiString(&StringPath,&ucDataBase,FALSE);
+
+ // this memory was allocated in OpenAndReadElement
+ //
+ CTEMemFree(ucDataBase.Buffer);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ // now put the "\lmhosts" name on the end of the string
+ //
+ RtlInitString(&LmhostsString,ascLmhosts);
+
+ status = RtlAppendStringToString(&StringPath,&LmhostsString);
+
+ if (NT_SUCCESS(status))
+ {
+ //
+ // is the first part of the directory "%SystemRoot%" ?
+ //
+ // If so, it must be changed to "\\SystemRoot\\".
+ //
+ // 0123456789 123456789 1
+ // %SystemRoot%\somewhere
+ //
+ //
+ if (strncmp(StringPath.Buffer, "%SystemRoot%", 12) == 0)
+ {
+
+ StringPath.Buffer[0] = '\\';
+ StringPath.Buffer[11] = '\\';
+ if (StringPath.Buffer[12] == '\\')
+ {
+ ASSERT(StringPath.Length >= 13);
+
+ if (StringPath.Length > 13)
+ {
+ RtlMoveMemory( // overlapped copy
+ &(StringPath.Buffer[12]), // Destination
+ &(StringPath.Buffer[13]), // Source
+ (ULONG) StringPath.Length - 13); // Length
+
+ StringPath.Buffer[StringPath.Length - 1] = (CHAR) NULL;
+ }
+
+ StringPath.Length--;
+ }
+ }
+ *ppPath = (PCHAR)StringPath.Buffer;
+ }
+ else
+ *ppPath = NULL;
+
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+ReadStringRelative(
+ IN PUNICODE_STRING pRegistryPath,
+ IN PWSTR pRelativePath,
+ IN PWSTR pValueName,
+ OUT PUNICODE_STRING pOutString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads a string from a registry key parallel to the
+ Netbt key - such as ..\tcpip\parameters\database
+
+Arguments:
+
+ pRegistryPath = ptr to the Netbt Registry path
+ pRelativePath = path to value relative to same root as nbt.
+ pValueName = value to read
+
+
+
+Return Value:
+
+ The length of the path up to and including the last slash and a ptr
+ to the first character of the last element of the string.
+
+--*/
+
+{
+ NTSTATUS status;
+ UNICODE_STRING RegistryPath;
+ UNICODE_STRING RelativePath;
+ ULONG StringMax;
+ PVOID pBuffer;
+ PWSTR pLastElement;
+ ULONG Length;
+
+ CTEPagedCode();
+
+ StringMax = (pRegistryPath->MaximumLength +
+ wcslen(pRelativePath)*sizeof(WCHAR)+2);
+ //
+ // allocate some memory for the registry path so that it is large enough
+ // to append a string on to, for the relative key to be read
+ //
+ pBuffer = NbtAllocMem(StringMax,NBT_TAG('i'));
+
+ if (!pBuffer)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ RegistryPath.MaximumLength = (USHORT)StringMax;
+ RegistryPath.Buffer = pBuffer;
+ RtlCopyUnicodeString(&RegistryPath,pRegistryPath);
+
+ //
+ // find the last backslash and truncate the string
+ NbtFindLastSlash(&RegistryPath,&pLastElement,&Length);
+ RegistryPath.Length = (USHORT)Length;
+
+ if (pLastElement)
+ {
+ *pLastElement = UNICODE_NULL;
+
+ RtlInitUnicodeString(&RelativePath,pRelativePath);
+
+ status = RtlAppendUnicodeStringToString(&RegistryPath,&RelativePath);
+
+ if (NT_SUCCESS(status))
+ {
+ status = OpenAndReadElement(&RegistryPath,pValueName,pOutString);
+
+ if (NT_SUCCESS(status))
+ {
+ // free the registry path
+ //
+ CTEMemFree(pBuffer);
+ return(status);
+ }
+ }
+ }
+ CTEMemFree(pBuffer);
+
+ return(status);
+}
+//----------------------------------------------------------------------------
+ VOID
+NbtFindLastSlash(
+ IN PUNICODE_STRING pucRegistryPath,
+ OUT PWSTR *ppucLastElement,
+ IN int *piLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Nbt to find the last slash in a registry
+ path name.
+
+Arguments:
+
+
+Return Value:
+
+ The length of the path up to and including the last slash and a ptr
+ to the first character of the last element of the string.
+
+--*/
+
+{
+ int i;
+ PWSTR pwsSlash = L"\\";
+ int iStart;
+
+ CTEPagedCode();
+
+ // search starting at the end of the string for the last back slash
+ iStart = wcslen(pucRegistryPath->Buffer)-1;
+ for(i=iStart;i>=0 ;i-- )
+ {
+ if (pucRegistryPath->Buffer[i] == *pwsSlash)
+ {
+ if (i==pucRegistryPath->Length-1)
+ {
+ // name ends a back slash... this is an error
+ break;
+ }
+ // increase one to allow for the slash
+ *piLength = (i+1)*sizeof(WCHAR);
+ if (ppucLastElement != NULL)
+ {
+ // want ptr to point at character after the slash
+ *ppucLastElement = &pucRegistryPath->Buffer[i+1];
+ }
+ return;
+ }
+ }
+
+ // null the pointer if one is passed in
+ if (ppucLastElement != NULL)
+ {
+ *ppucLastElement = NULL;
+ }
+ *piLength = 0;
+ return;
+}
diff --git a/private/ntos/nbt/nt/sources.inc b/private/ntos/nbt/nt/sources.inc
new file mode 100644
index 000000000..4fa44b266
--- /dev/null
+++ b/private/ntos/nbt/nt/sources.inc
@@ -0,0 +1,71 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nbt
+
+
+
+NTPROFILEINPUT=yes
+
+TARGETNAME=netbt
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(TARGETLIBS) \
+ $(BASEDIR)\public\sdk\lib\*\tdi.lib
+
+INCLUDES=..\..\inc;..\..\..\inc;..\..\..\..\inc
+!if "$(DS_BUILD)" == "1"
+INCLUDES=$(BASEDIR)\private\dsinc;$(INCLUDES)
+DSINC=..
+!endif
+
+C_DEFINES=$(C_DEFINES) -DWIN32 -DPROXY_NODE -D_NTDRIVER_ -DRASAUTODIAL -D_PNP_POWER=1 -D_IO_DELETE_DEVICE_SUPPORTED
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES= $(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES= \
+ ..\netbt.rc \
+ ..\ctestuff.c \
+ ..\driver.c \
+ ..\ntisol.c \
+ ..\ntutil.c \
+ ..\registry.c \
+ ..\tdiaddr.c \
+ ..\tdicnct.c \
+ ..\tdihndlr.c \
+ ..\fileio.c \
+ ..\winsif.c \
+ ..\tdiout.c \
+ ..\ntpnp.c \
+ ..\autodial.c
+
+
+PRECOMPILED_INCLUDE=..\..\nbtprocs.h
+PRECOMPILED_PCH=nbtprocs.pch
+PRECOMPILED_OBJ=nbtprocs.obj
diff --git a/private/ntos/nbt/nt/tdiaddr.c b/private/ntos/nbt/nt/tdiaddr.c
new file mode 100644
index 000000000..18dbff62f
--- /dev/null
+++ b/private/ntos/nbt/nt/tdiaddr.c
@@ -0,0 +1,672 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Tdihndlr.c
+
+Abstract:
+
+ This file contains code relating to manipulation of address objects
+ that is specific to the NT operating system. It creates address endpoints
+ with the transport provider.
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, NbtTdiOpenAddress)
+#pragma CTEMakePageable(PAGE, NbtTdiOpenControl)
+#pragma CTEMakePageable(PAGE, SetEventHandler)
+#pragma CTEMakePageable(PAGE, SubmitTdiRequest)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtTdiOpenAddress (
+ OUT PHANDLE pHandle,
+ OUT PDEVICE_OBJECT *ppDeviceObject,
+ OUT PFILE_OBJECT *ppFileObject,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN USHORT PortNumber,
+ IN ULONG IpAddress,
+ IN ULONG Flags
+ )
+/*++
+
+Routine Description:
+
+ Note: This synchronous call may take a number of seconds. It runs in
+ the context of the caller. The code Opens an Address object with the
+ transport provider and then sets up event handlers for Receive,
+ Disconnect, Datagrams and Errors.
+
+ THIS ROUTINE MUST BE CALLED IN THE CONTEXT OF THE FSP (I.E.
+ PROBABLY AN EXECUTIVE WORKER THREAD).
+
+ The address data structures are found in tdi.h , but they are rather
+ confusing since the definitions have been spread across several data types.
+ This section shows the complete data type for Ip address:
+
+ typedef struct
+ {
+ int TA_AddressCount;
+ struct _TA_ADDRESS
+ {
+ USHORT AddressType;
+ USHORT AddressLength;
+ struct _TDI_ADDRESS_IP
+ {
+ USHORT sin_port;
+ USHORT in_addr;
+ UCHAR sin_zero[8];
+ } TDI_ADDRESS_IP
+
+ } TA_ADDRESS[AddressCount];
+
+ } TRANSPORT_ADDRESS
+
+ An EA buffer is allocated (for the IRP), with an EA name of "TransportAddress"
+ and value is a structure of type TRANSPORT_ADDRESS.
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+
+
+ OBJECT_ATTRIBUTES AddressAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ NTSTATUS status;
+ PWSTR pNameTcp=L"Tcp";
+ PWSTR pNameUdp=L"Udp";
+ UNICODE_STRING ucDeviceName;
+ PTRANSPORT_ADDRESS pTransAddressEa;
+ PTRANSPORT_ADDRESS pTransAddr;
+ TDI_ADDRESS_IP IpAddr;
+ BOOLEAN Attached = FALSE;
+ PFILE_OBJECT pFileObject;
+ HANDLE FileHandle;
+
+ CTEPagedCode();
+ *ppFileObject = NULL;
+ *ppDeviceObject = NULL;
+ // copy device name into the unicode string - either Udp or Tcp
+ //
+ if (Flags & TCP_FLAG)
+ status = CreateDeviceString(pNameTcp,&ucDeviceName);
+ else
+ status = CreateDeviceString(pNameUdp,&ucDeviceName);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+ EaBuffer = NbtAllocMem(
+ sizeof(FILE_FULL_EA_INFORMATION) - 1 +
+ TDI_TRANSPORT_ADDRESS_LENGTH + 1 +
+ sizeof(TRANSPORT_ADDRESS) +
+ sizeof(TDI_ADDRESS_IP),NBT_TAG('j'));
+
+ if (EaBuffer == NULL)
+ {
+ ASSERTMSG(
+ (PCHAR)"Unable to get memory for an Eabuffer to open an address",
+ (PVOID)EaBuffer);
+ CTEMemFree(ucDeviceName.Buffer);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ EaBuffer->NextEntryOffset = 0;
+ EaBuffer->Flags = 0;
+ EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
+
+ EaBuffer->EaValueLength = sizeof(TRANSPORT_ADDRESS) -1
+ + sizeof(TDI_ADDRESS_IP);
+
+ IF_DBG(NBT_DEBUG_TDIADDR)
+ KdPrint(("EaValueLength = %d\n",EaBuffer->EaValueLength));
+
+ // put "TransportAddress" into the name
+ //
+ RtlMoveMemory(
+ EaBuffer->EaName,
+ TdiTransportAddress,
+ EaBuffer->EaNameLength + 1);
+
+ // fill in the IP address and Port number
+ //
+ pTransAddressEa = (TRANSPORT_ADDRESS *)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
+
+
+ // allocate Memory for the transport address
+ //
+ pTransAddr = NbtAllocMem(
+ sizeof(TDI_ADDRESS_IP)+sizeof(TRANSPORT_ADDRESS),NBT_TAG('k'));
+
+ pTransAddr->TAAddressCount = 1;
+ pTransAddr->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
+ pTransAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+
+ IpAddr.sin_port = htons(PortNumber); // put in network order
+ IpAddr.in_addr = htonl(IpAddress);
+
+ // zero fill the last component of the IP address
+ //
+ RtlFillMemory((PVOID)&IpAddr.sin_zero,
+ sizeof(IpAddr.sin_zero),
+ 0);
+
+ // copy the ip address to the end of the structure
+ //
+ RtlMoveMemory(pTransAddr->Address[0].Address,
+ (CONST PVOID)&IpAddr,
+ sizeof(IpAddr));
+
+ // copy the ip address to the end of the name in the EA structure
+ //
+ RtlMoveMemory((PVOID)pTransAddressEa,
+ (CONST PVOID)pTransAddr,
+ sizeof(TDI_ADDRESS_IP) + sizeof(TRANSPORT_ADDRESS)-1);
+
+
+ IF_DBG(NBT_DEBUG_TDIADDR)
+ KdPrint(("creating Address named %ws\n",ucDeviceName.Buffer));
+
+ InitializeObjectAttributes(
+ &AddressAttributes,
+ &ucDeviceName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ status = ZwCreateFile(
+ &FileHandle,
+ GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
+ &AddressAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN_IF,
+ 0,
+ (PVOID)EaBuffer,
+ sizeof(FILE_FULL_EA_INFORMATION) - 1 +
+ EaBuffer->EaNameLength + 1 +
+ EaBuffer->EaValueLength);
+
+ CTEMemFree((PVOID)pTransAddr);
+ CTEMemFree((PVOID)EaBuffer);
+ CTEMemFree(ucDeviceName.Buffer);
+
+ IF_DBG(NBT_DEBUG_TDIADDR)
+ KdPrint(("NBT:Failed Create (address) File, status = %X\n",status ));
+
+ if (NT_SUCCESS(status))
+ {
+ // if the ZwCreate passed set the status to the IoStatus
+ status = IoStatusBlock.Status;
+
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("Nbt:Failed to Open the Address to the transport, status = %X\n",
+ status));
+
+ return(status);
+ }
+
+ // dereference the file object to keep the device ptr around to avoid
+ // this dereference at run time
+ //
+ status = ObReferenceObjectByHandle(
+ FileHandle,
+ (ULONG)0,
+ 0,
+ KernelMode,
+ (PVOID *)&pFileObject,
+ NULL);
+
+ if (NT_SUCCESS(status))
+ {
+ // return the handle to the caller
+ //
+ *pHandle = FileHandle;
+ //
+ // return the parameter to the caller
+ //
+ *ppFileObject = pFileObject;
+
+ *ppDeviceObject = IoGetRelatedDeviceObject(*ppFileObject);
+
+ status = SetEventHandler(
+ *ppDeviceObject,
+ *ppFileObject,
+ TDI_EVENT_ERROR,
+ (PVOID)TdiErrorHandler,
+ (PVOID)pDeviceContext);
+
+ if (NT_SUCCESS(status))
+ {
+ // if this is a TCP address being opened, then create different
+ // event handlers for connections
+ //
+ if (Flags & TCP_FLAG)
+ {
+ status = SetEventHandler(
+ *ppDeviceObject,
+ *ppFileObject,
+ TDI_EVENT_RECEIVE,
+ (PVOID)TdiReceiveHandler,
+ (PVOID)pDeviceContext);
+
+ if (NT_SUCCESS(status))
+ {
+ status = SetEventHandler(
+ *ppDeviceObject,
+ *ppFileObject,
+ TDI_EVENT_DISCONNECT,
+ (PVOID)TdiDisconnectHandler,
+ (PVOID)pDeviceContext);
+
+ if (NT_SUCCESS(status))
+ {
+ // only set a connect handler if the session flag is set.
+ // In this case the address being opened is the Netbios session
+ // port 139
+ //
+ if (Flags & SESSION_FLAG)
+ {
+ status = SetEventHandler(
+ *ppDeviceObject,
+ *ppFileObject,
+ TDI_EVENT_CONNECT,
+ (PVOID)TdiConnectHandler,
+ (PVOID)pDeviceContext);
+
+ if (NT_SUCCESS(status))
+ {
+ return(status);
+ }
+
+ }
+ else
+ return(status);
+ }
+ }
+
+
+ }
+ else
+ {
+ // Datagram ports only need this event handler
+ if (PortNumber == NBT_DATAGRAM_UDP_PORT)
+ {
+ // Datagram Udp Handler
+ status = SetEventHandler(
+ *ppDeviceObject,
+ *ppFileObject,
+ TDI_EVENT_RECEIVE_DATAGRAM,
+ (PVOID)TdiRcvDatagramHandler,
+ (PVOID)pDeviceContext);
+ if (NT_SUCCESS(status))
+ {
+ return(status);
+ }
+ }
+ else
+ {
+ // Name Service Udp handler
+ status = SetEventHandler(
+ *ppDeviceObject,
+ *ppFileObject,
+ TDI_EVENT_RECEIVE_DATAGRAM,
+ (PVOID)TdiRcvNameSrvHandler,
+ (PVOID)pDeviceContext);
+
+ if (NT_SUCCESS(status))
+ {
+ return(status);
+ }
+ }
+ }
+
+ //
+ // ERROR Case
+ //
+ ObDereferenceObject(pFileObject);
+ ZwClose(FileHandle);
+
+ return(status);
+ }
+
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_TDIADDR)
+ KdPrint(("Failed Open Address (Dereference Object) status = %X\n",
+ status));
+
+ ZwClose(FileHandle);
+ }
+
+ }
+
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtTdiOpenControl (
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine opens a control object with the transport. It is very similar
+ to opening an address object, above.
+
+Arguments:
+
+
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PWSTR pName=L"Tcp";
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ UNICODE_STRING DeviceName;
+ BOOLEAN Attached = FALSE;
+
+
+ CTEPagedCode();
+ // copy device name into the unicode string
+ Status = CreateDeviceString(pName,&DeviceName);
+ if (!NT_SUCCESS(Status))
+ {
+ return(Status);
+ }
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ &DeviceName,
+ 0,
+ NULL,
+ NULL);
+
+ IF_DBG(NBT_DEBUG_TDIADDR)
+ KdPrint(("tcp device to open = %ws\n",DeviceName.Buffer));
+
+ EaBuffer = NULL;
+
+ Status = ZwCreateFile (
+ (PHANDLE)&pDeviceContext->hControl,
+ GENERIC_READ | GENERIC_WRITE,
+ &ObjectAttributes, // object attributes.
+ &IoStatusBlock, // returned status information.
+ NULL, // block size (unused).
+ FILE_ATTRIBUTE_NORMAL, // file attributes.
+ 0,
+ FILE_CREATE,
+ 0, // create options.
+ (PVOID)EaBuffer, // EA buffer.
+ 0); // Ea length
+
+
+ CTEMemFree(DeviceName.Buffer);
+
+ IF_DBG(NBT_DEBUG_TDIADDR)
+ KdPrint( ("OpenControl CreateFile Status:%X, IoStatus:%X\n", Status, IoStatusBlock.Status));
+
+ if ( NT_SUCCESS( Status ))
+ {
+ // if the ZwCreate passed set the status to the IoStatus
+ Status = IoStatusBlock.Status;
+
+ if (!NT_SUCCESS(Status))
+ {
+ IF_DBG(NBT_DEBUG_TDIADDR)
+ KdPrint(("Nbt:Failed to Open the control connection to the transport, status = %X\n",
+ Status));
+
+ }
+ else
+ {
+ // get a reference to the file object and save it since we can't
+ // dereference a file handle at DPC level so we do it now and keep
+ // the ptr around for later.
+ Status = ObReferenceObjectByHandle(
+ pDeviceContext->hControl,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *)&pDeviceContext->pControlFileObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status))
+ {
+ ZwClose(pDeviceContext->hControl);
+ }
+ else
+ pDeviceContext->pControlDeviceObject =
+ IoGetRelatedDeviceObject(pDeviceContext->pControlFileObject);
+ }
+
+ }
+ else
+ {
+ KdPrint(("Nbt:Failed to Open the control connection to the transport, status1 = %X\n",
+ Status));
+
+ // set control file object ptr to null so we know that we didnot open
+ // the control point.
+ //
+ pDeviceContext->pControlFileObject = NULL;
+ }
+
+ return Status;
+
+} /* NbtTdiOpenConnection */
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+CompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This routine does not complete the Irp. It is used to signal to a
+ synchronous part of the NBT driver that it can proceed (i.e.
+ to allow some code that is waiting on a "KeWaitForSingleObject" to
+ proceeed.
+
+Arguments:
+
+ DeviceObject - unused.
+
+ Irp - Supplies Irp that the transport has finished processing.
+
+ Context - Supplies the event associated with the Irp.
+
+Return Value:
+
+ The STATUS_MORE_PROCESSING_REQUIRED so that the IO system stops
+ processing Irp stack locations at this point.
+
+--*/
+{
+ IF_DBG(NBT_DEBUG_TDIADDR)
+ KdPrint( ("Completion event: %X, Irp: %X, DeviceObject: %X\n",
+ Context,
+ Irp,
+ DeviceObject));
+
+ KeSetEvent((PKEVENT )Context, 0, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ UNREFERENCED_PARAMETER( DeviceObject );
+ UNREFERENCED_PARAMETER( Irp );
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+SetEventHandler (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PFILE_OBJECT FileObject,
+ IN ULONG EventType,
+ IN PVOID EventHandler,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine registers an event handler with a TDI transport provider.
+
+Arguments:
+
+ IN PDEVICE_OBJECT DeviceObject - Supplies the device object of the transport provider.
+ IN PFILE_OBJECT FileObject - Supplies the address object's file object.
+ IN ULONG EventType, - Supplies the type of event.
+ IN PVOID EventHandler - Supplies the event handler.
+ IN PVOID Context - Supplies the context passed into the event handler when it runs
+
+Return Value:
+
+ NTSTATUS - Final status of the set event operation
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIRP Irp;
+
+ CTEPagedCode();
+ Irp = IoAllocateIrp(IoGetRelatedDeviceObject(FileObject)->StackSize, FALSE);
+
+ if (Irp == NULL)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ TdiBuildSetEventHandler(Irp, DeviceObject, FileObject,
+ NULL, NULL,
+ EventType, EventHandler, Context);
+
+ Status = SubmitTdiRequest(FileObject, Irp);
+
+ IoFreeIrp(Irp);
+
+ return Status;
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+SubmitTdiRequest (
+ IN PFILE_OBJECT FileObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine submits a request to TDI and waits for it to complete.
+
+Arguments:
+
+ IN PFILE_OBJECT FileObject - Connection or Address handle for TDI request
+ IN PIRP Irp - TDI request to submit.
+
+Return Value:
+
+ NTSTATUS - Final status of request.
+
+--*/
+
+{
+ KEVENT Event;
+ NTSTATUS Status;
+
+
+ CTEPagedCode();
+ KeInitializeEvent (&Event, NotificationEvent, FALSE);
+
+ // set the address of the routine to be executed when the IRP
+ // finishes. This routine signals the event and allows the code
+ // below to continue (i.e. KeWaitForSingleObject)
+ //
+ IoSetCompletionRoutine(Irp,
+ (PIO_COMPLETION_ROUTINE)CompletionRoutine,
+ (PVOID)&Event,
+ TRUE, TRUE, TRUE);
+
+ CHECK_COMPLETION(Irp);
+ Status = IoCallDriver(IoGetRelatedDeviceObject(FileObject), Irp);
+
+ //
+ // If it failed immediately, return now, otherwise wait.
+ //
+
+ if (!NT_SUCCESS(Status))
+ {
+ KdPrint(("Failed to Submit Tdi Request, status = %X\n",Status));
+ return Status;
+ }
+
+ if (Status == STATUS_PENDING)
+ {
+
+ Status = KeWaitForSingleObject((PVOID)&Event, // Object to wait on.
+ Executive, // Reason for waiting
+ KernelMode, // Processor mode
+ FALSE, // Alertable
+ NULL); // Timeout
+
+ if (!NT_SUCCESS(Status))
+ {
+ KdPrint(("Failed on return from KeWaitForSingleObj in Set Event Handler, status = %X\n",
+ Status));
+ return Status;
+ }
+
+ Status = Irp->IoStatus.Status;
+
+ IF_DBG(NBT_DEBUG_TDIADDR)
+ KdPrint(("Io Status from setting event = %X\n",Status));
+ }
+
+ return(Status);
+}
+
+
+
diff --git a/private/ntos/nbt/nt/tdicnct.c b/private/ntos/nbt/nt/tdicnct.c
new file mode 100644
index 000000000..3ff5610e4
--- /dev/null
+++ b/private/ntos/nbt/nt/tdicnct.c
@@ -0,0 +1,530 @@
+//
+//
+// NBTCONNCT.C
+//
+// This file contains code relating to opening connections with the transport
+// provider. The Code is NT specific.
+
+#include "nbtprocs.h"
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, NbtTdiOpenConnection)
+#pragma CTEMakePageable(PAGE, NbtTdiAssociateConnection)
+#pragma CTEMakePageable(PAGE, TdiOpenandAssocConnection)
+#pragma CTEMakePageable(PAGE, NbtTdiCloseConnection)
+#pragma CTEMakePageable(PAGE, CreateDeviceString)
+#pragma CTEMakePageable(PAGE, NbtTdiCloseAddress)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtTdiOpenConnection (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine opens a connection with the transport provider.
+
+Arguments:
+
+ pLowerConn - Pointer to where the handle to the Transport for this virtual
+ connection should be stored.
+
+ pNbtConfig - the name of the adapter to connect to is in this structure
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PWSTR pName=L"Tcp";
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ UNICODE_STRING DeviceName;
+ PMDL pMdl;
+ PVOID pBuffer;
+ BOOLEAN Attached = FALSE;
+
+ CTEPagedCode();
+ // zero out the connection data structure
+ CTEZeroMemory(pLowerConn,sizeof(tLOWERCONNECTION));
+ pLowerConn->State = NBT_IDLE;
+ pLowerConn->pDeviceContext = pDeviceContext;
+ pLowerConn->RefCount = 1;
+ pLowerConn->LockNumber = LOWERCON_LOCK;
+ pLowerConn->Verify = NBT_VERIFY_LOWERCONN;
+
+ Status = CreateDeviceString(pName,&DeviceName);
+ if (!NT_SUCCESS(Status))
+ {
+ return(Status);
+ }
+
+ //
+ // Allocate an MDL for the Indication buffer since we may need to buffer
+ // up to 128 bytes
+ //
+ pBuffer = NbtAllocMem(NBT_INDICATE_BUFFER_SIZE,NBT_TAG('l'));
+
+ if (!pBuffer)
+ {
+ CTEMemFree(DeviceName.Buffer);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pMdl = IoAllocateMdl(pBuffer,NBT_INDICATE_BUFFER_SIZE,FALSE,FALSE,NULL);
+
+ if (pMdl)
+ {
+
+ MmBuildMdlForNonPagedPool(pMdl);
+
+ pLowerConn->pIndicateMdl = pMdl;
+
+
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ &DeviceName,
+ 0,
+ NULL,
+ NULL);
+
+ IF_DBG(NBT_DEBUG_TDICNCT)
+ KdPrint(("tcp device to open = %ws\n",DeviceName.Buffer));
+
+ // Allocate memory for the address info to be passed to the transport
+ EaBuffer = (PFILE_FULL_EA_INFORMATION)NbtAllocMem (
+ sizeof(FILE_FULL_EA_INFORMATION) - 1 +
+ TDI_CONNECTION_CONTEXT_LENGTH + 1 +
+ sizeof(CONNECTION_CONTEXT),NBT_TAG('m'));
+
+ if (EaBuffer)
+ {
+
+ EaBuffer->NextEntryOffset = 0;
+ EaBuffer->Flags = 0;
+ EaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
+ EaBuffer->EaValueLength = sizeof (CONNECTION_CONTEXT);
+
+ // TdiConnectionContext is a macro that = "ConnectionContext" - so move
+ // this text to EaName
+ RtlMoveMemory( EaBuffer->EaName, TdiConnectionContext, EaBuffer->EaNameLength + 1 );
+
+ // put the context value into the EaBuffer too - i.e. the value that the
+ // transport returns with each indication on this connection
+ RtlMoveMemory (
+ (PVOID)&EaBuffer->EaName[EaBuffer->EaNameLength + 1],
+ (CONST PVOID)&pLowerConn,
+ sizeof (CONNECTION_CONTEXT));
+
+ {
+
+ Status = ZwCreateFile (
+ &pLowerConn->FileHandle,
+ GENERIC_READ | GENERIC_WRITE,
+ &ObjectAttributes, // object attributes.
+ &IoStatusBlock, // returned status information.
+ NULL, // block size (unused).
+ FILE_ATTRIBUTE_NORMAL, // file attributes.
+ 0,
+ FILE_CREATE,
+ 0, // create options.
+ (PVOID)EaBuffer, // EA buffer.
+ sizeof(FILE_FULL_EA_INFORMATION) - 1 +
+ TDI_CONNECTION_CONTEXT_LENGTH + 1 +
+ sizeof(CONNECTION_CONTEXT)
+ );
+ }
+
+ IF_DBG(NBT_DEBUG_TDICNCT)
+ KdPrint( ("OpenConnection CreateFile Status:%X, IoStatus:%X\n", Status, IoStatusBlock.Status));
+
+ CTEMemFree((PVOID)EaBuffer);
+
+ if ( NT_SUCCESS( Status ))
+ {
+
+ // if the ZwCreate passed set the status to the IoStatus
+ //
+ Status = IoStatusBlock.Status;
+
+ if (NT_SUCCESS(Status))
+ {
+ // get a reference to the file object and save it since we can't
+ // dereference a file handle at DPC level so we do it now and keep
+ // the ptr around for later.
+ Status = ObReferenceObjectByHandle(
+ pLowerConn->FileHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *)&pLowerConn->pFileObject,
+ NULL);
+
+ if (NT_SUCCESS(Status))
+ {
+ CTEMemFree(DeviceName.Buffer);
+ return(Status);
+ }
+
+ ZwClose(pLowerConn->FileHandle);
+
+ }
+
+ }
+
+ }
+ else
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ IoFreeMdl(pMdl);
+ }
+ else
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ CTEMemFree(pBuffer);
+ CTEMemFree(DeviceName.Buffer);
+
+ return Status;
+
+} /* NbtTdiOpenConnection */
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtTdiAssociateConnection(
+ IN PFILE_OBJECT pFileObject,
+ IN HANDLE Handle
+ )
+/*++
+
+Routine Description:
+
+ This routine associates an open connection with the address object.
+
+Arguments:
+
+
+ pFileObject - the connection file object
+ Handle - the address object to associate the connection with
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ PIRP pIrp;
+ KEVENT Event;
+ BOOLEAN Attached = FALSE;
+
+ CTEPagedCode();
+
+ KeInitializeEvent(
+ &Event,
+ SynchronizationEvent,
+ FALSE);
+
+ pIrp = NTAllocateNbtIrp(IoGetRelatedDeviceObject(pFileObject));
+
+ if (!pIrp)
+ {
+ KdPrint(("NBT:Failed to build internal device Irp\n"));
+ return(STATUS_UNSUCCESSFUL);
+ }
+
+ TdiBuildAssociateAddress (
+ pIrp,
+ pFileObject->DeviceObject,
+ pFileObject,
+ CompletionRoutine,
+ &Event,
+ Handle);
+
+ status = SubmitTdiRequest(pFileObject,pIrp);
+
+ IoFreeIrp(pIrp);
+
+ return status;
+
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+CreateDeviceString(
+ IN PWSTR AppendingString,
+ IN OUT PUNICODE_STRING pucDeviceName
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a string name for the transport device such as
+ "\Device\Streams\Tcp"
+
+Arguments:
+
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ ULONG Len;
+ PVOID pBuffer;
+
+ CTEPagedCode();
+ // copy device name into the unicode string - either Udp or Tcp
+ //
+ Len = (wcslen(NbtConfig.pTcpBindName) + wcslen(AppendingString) + 1) * sizeof(WCHAR);
+
+ pBuffer = NbtAllocMem(Len,NBT_TAG('n'));
+ if (!pBuffer)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pucDeviceName->MaximumLength = (USHORT)Len;
+ pucDeviceName->Length = 0;
+ pucDeviceName->Buffer = pBuffer;
+
+ // this puts \Device\Streams into the string
+ //
+ status = RtlAppendUnicodeToString(pucDeviceName,NbtConfig.pTcpBindName);
+ if (NT_SUCCESS(status))
+ {
+ status = RtlAppendUnicodeToString (pucDeviceName,AppendingString);
+ }
+ else
+ CTEMemFree(pBuffer);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiOpenandAssocConnection(
+ IN tCONNECTELE *pConnEle,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN ULONG PortNumber
+ )
+/*++
+
+Routine Description:
+
+ This routine opens and associates an open connection.
+
+ This routine is called with the Spin Lock held on the pConnele. It is
+ released in this routine.
+
+Arguments:
+
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ NTSTATUS Locstatus;
+ PDEVICE_OBJECT pDeviceObject;
+ tLOWERCONNECTION *pLowerConn;
+ BOOLEAN Attached=FALSE;
+
+ CTEPagedCode();
+
+ CTEAttachFsp(&Attached);
+
+ // allocate memory for the lower connection block.
+ //
+ pConnEle->pLowerConnId = (PVOID)NbtAllocMem(sizeof(tLOWERCONNECTION),NBT_TAG('o'));
+
+ if (!pConnEle->pLowerConnId)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // fill in the lower connection element to point to the upper one and
+ // vice versa
+ //
+ pLowerConn = pConnEle->pLowerConnId;
+
+ status = NbtTdiOpenConnection(pLowerConn,pDeviceContext);
+ if (!NT_SUCCESS(status))
+ {
+ CTEDetachFsp(Attached);
+ CTEMemFree((PVOID)pConnEle->pLowerConnId);
+ pConnEle->pLowerConnId = NULL;
+ return(status);
+ }
+
+ pLowerConn->pUpperConnection = pConnEle;
+ pLowerConn->State = NBT_IDLE;
+
+ //
+ // until the correct state proc is set (i.e.Outbound), reject any data
+ // (in other words, don't let this field stay NULL!)
+ //
+ SetStateProc( pLowerConn, RejectAnyData ) ;
+
+
+ if (NT_SUCCESS(status))
+ {
+
+ // Open an address object (aka port)
+ //
+ status = NbtTdiOpenAddress(
+ &pLowerConn->AddrFileHandle,
+ &pDeviceObject, // dummy argument, not used here
+ &pLowerConn->pAddrFileObject,
+ pDeviceContext,
+ (USHORT)PortNumber, // port
+ pDeviceContext->IpAddress,
+ TCP_FLAG);
+
+ if (NT_SUCCESS(status))
+ {
+ // now associate the two
+ status = NbtTdiAssociateConnection(
+ pLowerConn->pFileObject,
+ pLowerConn->AddrFileHandle);
+
+
+ if (NT_SUCCESS(status))
+ {
+ CTEDetachFsp(Attached);
+ //
+ // put the lower connection on the Q of active lower connections for
+ // this device
+ //
+ ExInterlockedInsertTailList(&pDeviceContext->LowerConnection,
+ &pLowerConn->Linkage,
+ &pDeviceContext->SpinLock);
+
+ return(status);
+ }
+
+ ObDereferenceObject(pLowerConn->pAddrFileObject);
+ Locstatus = ZwClose(pLowerConn->AddrFileHandle);
+
+ }
+ KdPrint(("Nbt:Open Xport Address Failed, status %X\n",status));
+
+ ObDereferenceObject(pLowerConn->pFileObject);
+ Locstatus = ZwClose(pLowerConn->FileHandle);
+
+ }
+
+ CTEDetachFsp(Attached);
+
+ // Error Path... delete memory
+ //
+ pConnEle->pLowerConnId = NULL;
+ CTEMemFree((PVOID)pLowerConn);
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+
+NTSTATUS
+NbtTdiCloseConnection(
+ IN tLOWERCONNECTION * pLowerConn
+ )
+/*++
+
+Routine Description:
+
+ This routine closes a TDI connection
+
+Arguments:
+
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ BOOLEAN Attached= FALSE;
+
+ CTEPagedCode();
+ ASSERT( pLowerConn != NULL ) ;
+
+ CTEAttachFsp(&Attached);
+
+ if (pLowerConn->FileHandle) {
+ status = ZwClose(pLowerConn->FileHandle);
+ pLowerConn->FileHandle = NULL;
+ }
+
+#if DBG
+ if (!NT_SUCCESS(status))
+ KdPrint(("Nbt:Failed to close Connection FileHandle pLower %X, status %X\n",pLowerConn,status));
+#endif
+
+ CTEDetachFsp(Attached);
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+NTSTATUS
+NbtTdiCloseAddress(
+ IN tLOWERCONNECTION * pLowerConn
+ )
+/*++
+
+Routine Description:
+
+ This routine closes a TDI address
+
+Arguments:
+
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ BOOLEAN Attached= FALSE;
+
+ CTEPagedCode();
+
+ ASSERT( pLowerConn != NULL ) ;
+
+ CTEAttachFsp(&Attached);
+
+ status = ZwClose(pLowerConn->AddrFileHandle);
+#if DBG
+ if (!NT_SUCCESS(status))
+ KdPrint(("Nbt:Failed to close Address FileHandle pLower %X,status %X\n",pLowerConn,status));
+#endif
+
+ CTEDetachFsp(Attached);
+
+ return(status);
+
+}
diff --git a/private/ntos/nbt/nt/tdihndlr.c b/private/ntos/nbt/nt/tdihndlr.c
new file mode 100644
index 000000000..bcd515d97
--- /dev/null
+++ b/private/ntos/nbt/nt/tdihndlr.c
@@ -0,0 +1,6286 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Tdihndlr.c
+
+Abstract:
+
+
+ This file contains the TDI handlers that are setup for Connects,
+ Receives, Disconnects, and Errors on various objects such as connections
+ and udp endpoints .
+
+ This file represents the inbound TDI interface on the Bottom of NBT. Therefore
+ the code basically decodes the incoming information and passes it to
+ a non-Os specific routine to do what it can. Upon return from that
+ routine additional Os specific work may need to be done.
+
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+#include "ctemacro.h"
+
+// this macro checks that the types field is always zero in the Session
+// Pdu
+//
+#if DBG
+#define CHECK_PDU( _Size,_Offset) \
+ if (_Size > 1) \
+ ASSERT(((PUCHAR)pTsdu)[_Offset] == 0)
+#else
+#define CHECK_PDU( _Size,_Offset )
+#endif
+
+#if DBG
+UCHAR pLocBuff[256];
+UCHAR CurrLoc;
+
+ULONG R1;
+ULONG R2;
+ULONG R3;
+ULONG R4;
+
+ULONG C1;
+ULONG C2;
+ULONG C3;
+ULONG C4;
+
+
+#define INCR_COUNT(_Count) _Count++
+#else
+#define INCR_COUNT(_Count)
+#endif
+
+
+//
+// This ntohl swaps just three bytes, since the 4th byte could be a session
+// keep alive message type.
+//
+__inline long
+myntohl(long x)
+{
+ return((((x) >> 24) & 0x000000FFL) |
+ (((x) >> 8) & 0x0000FF00L) |
+ (((x) << 8) & 0x00FF0000L));
+}
+
+NTSTATUS
+LessThan4BytesRcvd(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ OUT PVOID *ppIrp
+ );
+NTSTATUS
+ClientTookSomeOfTheData(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ IN ULONG BytesTaken,
+ IN ULONG PduSize
+ );
+NTSTATUS
+MoreDataRcvdThanNeeded(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PVOID *ppIrp
+ );
+NTSTATUS
+NotEnoughDataYet(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN ULONG PduSize,
+ OUT PVOID *ppIrp
+ );
+NTSTATUS
+ProcessIrp(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN PIRP pIrp,
+ IN PVOID pBuffer,
+ IN PULONG BytesTaken,
+ IN ULONG BytesIndicted,
+ IN ULONG BytesAvailable
+ );
+
+NTSTATUS
+NtBuildIndicateForReceive (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG Length,
+ OUT PVOID *ppIrp
+ );
+
+NTSTATUS
+AcceptCompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ );
+
+VOID
+DpcNextOutOfRsrcKill(
+ IN PKDPC pDpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+VOID
+DpcGetRestOfIndication(
+ IN PKDPC pDpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+NTSTATUS
+ClientBufferOverFlow(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tCONNECTELE *pConnEle,
+ IN PIRP pIrp,
+ IN ULONG BytesRcvd
+ );
+VOID
+DpcHandleNewSessionPdu (
+ IN PKDPC pDpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+VOID
+HandleNewSessionPdu (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG Offset,
+ IN ULONG ToGet
+ );
+NTSTATUS
+NewSessionCompletionRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ );
+NTSTATUS
+BuildIrpForNewSessionInIndication (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN PIRP pIrpIn,
+ IN ULONG BytesAvailable,
+ IN ULONG RemainingPdu,
+ OUT PIRP *ppIrp
+ );
+VOID
+TrackIndicatedBytes(
+ IN ULONG BytesIndicated,
+ IN ULONG BytesTaken,
+ IN tCONNECTELE *pConnEle
+ );
+
+__inline
+ VOID
+DerefLowerConnFast (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tCONNECTELE *pConnEle,
+ IN CTELockHandle OldIrq
+ );
+
+NTSTATUS
+CopyDataandIndicate(
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PIRP *ppIrp
+ );
+
+VOID
+SumMdlLengths (
+ IN PMDL pMdl,
+ IN ULONG BytesAvailable,
+ IN tCONNECTELE *pConnectEle
+ );
+
+
+
+NTSTATUS
+RsrcKillCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ );
+
+VOID
+FillIrpCancelRoutine(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+NameSrvCompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+//----------------------------------------------------------------------------
+__inline
+ NTSTATUS
+Normal(
+ IN PVOID ReceiveEventContext,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PVOID *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive event indication handler.
+
+ It is called when an session packet arrives from the network. It calls
+ a non OS specific routine to decide what to do. That routine passes back
+ either a RcvElement (buffer) or a client rcv handler to call.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+ ASSERTMSG("Should not execute this procedure",0);
+ return(STATUS_SUCCESS);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+LessThan4BytesRcvd(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ OUT PVOID *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the case when data has arrived on a connection but
+ there isn't 128 bytes yet or a whole pdu.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ tCONNECTELE *pConnectEle;
+ NTSTATUS status;
+
+ // for short indications less than 4 bytes we can't determine
+ // the pdu size so just get the header first then get the
+ // whole pdu next.
+
+ status = NtBuildIrpForReceive(pLowerConn,
+ sizeof(tSESSIONHDR),
+ (PVOID *)ppIrp);
+
+ pConnectEle = pLowerConn->pUpperConnection;
+
+ pConnectEle->BytesInXport = BytesAvailable;
+
+ if (!NT_SUCCESS(status))
+ {
+ CTESpinFreeAtDpc(pLowerConn);
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLockAtDpc(pLowerConn);
+ return( STATUS_DATA_NOT_ACCEPTED);
+ }
+ //
+ // set the irp mdl length to size of session hdr so that
+ // we don't get more than one session pdu into the buffer
+ //
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+ pLowerConn->CurrentStateProc = IndicateBuffer;
+
+ *BytesTaken = 0;
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Switching to Ind Buff(<4 bytes), Avail = %X\n",
+ BytesAvailable));
+
+ PUSH_LOCATION(0);
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+ClientTookSomeOfTheData(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ IN ULONG BytesTaken,
+ IN ULONG PduSize
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the case when data has arrived on a connection but
+ the client has not taken all of the data indicated to it.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ tCONNECTELE *pConnectEle;
+
+ //
+ // took some of the data, so keep track of the
+ // rest of the data left here by going to the PARTIALRCV
+ // state.
+ //
+ PUSH_LOCATION(0x5);
+
+ pLowerConn->StateRcv = PARTIAL_RCV;
+ pLowerConn->CurrentStateProc = PartialRcv;
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Switch to Partial Rcv Indicated=%X, PduSize=%X\n",
+ BytesIndicated,PduSize-4));
+
+ // Note: PduSize must include the 4 byte session header for this to
+ // work correctly.
+ //
+ pConnectEle = pLowerConn->pUpperConnection;
+ //
+ // We always indicate the whole Pdu size to the client, so the amount
+ // indicated is that minus what was taken - typically the 4 byte
+ // session hdr
+ //
+ pConnectEle->ReceiveIndicated = PduSize - BytesTaken;
+ ASSERT(pConnectEle->ReceiveIndicated <= 0x20000);
+
+ // amount left in the transport...
+ pConnectEle->BytesInXport = BytesAvailable - BytesTaken;
+
+ // need to return this status since we took the 4 bytes
+ // session header at least, even if the client took none.
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+MoreDataRcvdThanNeeded(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PVOID *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the case when data has arrived on a connection but
+ there isn't 128 bytes yet or a whole pdu.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ tCONNECTELE *pConnectEle;
+ ULONG Length;
+ ULONG Remaining;
+ ULONG PduSize;
+ NTSTATUS status;
+ tSESSIONHDR UNALIGNED *pSessionHdr;
+
+
+ PUSH_LOCATION(0x6);
+ //
+ // there is too much data, so keep track of the
+ // fact that there is data left in the transport
+ // and get it with the indicate buffer
+ //
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+
+
+ ASSERT(pLowerConn->BytesInIndicate == 0);
+#if DBG
+ if (pLowerConn->BytesInIndicate)
+ {
+ KdPrint(("Nbt:Bytes in indicate should be ZERO, but are = %X\n",
+ pLowerConn->BytesInIndicate));
+ }
+#endif
+ pLowerConn->CurrentStateProc = IndicateBuffer;
+ pConnectEle = pLowerConn->pUpperConnection;
+
+ pConnectEle->BytesInXport = BytesAvailable - *BytesTaken;
+
+ //
+ // for short indications less than 4 bytes we can't determine
+ // the pdu size so just get the header first then get the
+ // whole pdu next.
+ //
+ Remaining = BytesIndicated - *BytesTaken;
+ if (Remaining < sizeof(tSESSIONHDR))
+ {
+ status = NtBuildIrpForReceive(pLowerConn,sizeof(tSESSIONHDR),(PVOID *)ppIrp);
+ if (!NT_SUCCESS(status))
+ {
+ // this is a serious error - we must
+ // kill of the connection and let the
+ // redirector restart it
+ KdPrint(("Nbt:Unable to get an Irp for RCv - Closing Connection!! %X\n",pLowerConn));
+ CTESpinFreeAtDpc(pLowerConn);
+
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLockAtDpc(pLowerConn);
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:< 4 Bytes,BytesTaken=%X,Avail=%X,Ind=%X,Remain=%X\n",
+ *BytesTaken,BytesAvailable,BytesIndicated,
+ Remaining));
+
+ // DEBUG
+ CTEZeroMemory(MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl),
+ NBT_INDICATE_BUFFER_SIZE);
+
+ PUSH_LOCATION(0x7);
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+ }
+ else
+ {
+ // if we get to here there are enough bytes left to determine
+ // the next pdu size...so we can determine how much
+ // data to get for the indicate buffer
+ //
+ pSessionHdr = (tSESSIONHDR UNALIGNED *)((PUCHAR)pTsdu + *BytesTaken);
+
+ PduSize = myntohl(pSessionHdr->UlongLength) + sizeof(tSESSIONHDR);
+
+
+ Length = (PduSize > NBT_INDICATE_BUFFER_SIZE) ?
+ NBT_INDICATE_BUFFER_SIZE : PduSize;
+
+ //
+ // The NewSessionCompletion routine recalculates
+ // what is left in the transport when the
+ // irp completes
+ //
+ status = NtBuildIrpForReceive(pLowerConn,Length,(PVOID *)ppIrp);
+ if (!NT_SUCCESS(status))
+ {
+ // this is a serious error - we must
+ // kill of the connection and let the
+ // redirector restart it
+ KdPrint(("Nbt:Unable to get an Irp for RCV(2) - Closing Connection!! %X\n",pLowerConn));
+ CTESpinFreeAtDpc(pLowerConn);
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLockAtDpc(pLowerConn);
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Switch to Ind Buff, InXport = %X, Pdusize=%X,ToGet=%X\n",
+ pConnectEle->BytesInXport,PduSize-4,Length));
+
+ }
+
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NotEnoughDataYet(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN ULONG PduSize,
+ OUT PVOID *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the case when data has arrived on a connection but
+ there isn't 128 bytes yet or a whole pdu.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ tCONNECTELE *pConnectEle;
+ ULONG Length;
+
+ PUSH_LOCATION(0x9);
+ //
+ // not enough data indicated, so use the indicate buffer
+ //
+ Length = (PduSize > NBT_INDICATE_BUFFER_SIZE) ?
+ NBT_INDICATE_BUFFER_SIZE : PduSize;
+
+ status = NtBuildIrpForReceive(pLowerConn,Length,(PVOID *)ppIrp);
+ if (!NT_SUCCESS(status))
+ {
+ CTESpinFreeAtDpc(pLowerConn);
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLockAtDpc(pLowerConn);
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ *BytesTaken = 0;
+
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+ pLowerConn->CurrentStateProc = IndicateBuffer;
+
+ pConnectEle = pLowerConn->pUpperConnection;
+ pConnectEle->BytesInXport = BytesAvailable;
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Not Enough data indicated in Tdihndlr, using indic. buffer Indicated = %X,Avail=%X,PduSize= %X\n",
+ BytesIndicated, BytesAvailable,PduSize-4));
+
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+FillIrp(
+ IN PVOID ReceiveEventContext,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PVOID *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive event indication handler.
+
+ It is called when an session packet arrives from the network. It calls
+ a non OS specific routine to decide what to do. That routine passes back
+ either a RcvElement (buffer) or a client rcv handler to call.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+ ASSERTMSG("Should not execute this procedure",0);
+ return(STATUS_SUCCESS);
+ // do nothing
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+IndicateBuffer(
+ IN PVOID ReceiveEventContext,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PVOID *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles reception of data while in the IndicateBuffer state.
+ In this state the indicate buffer is receiveing data until at least
+ 128 bytes have been receive, or a whole pdu has been received.
+
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ tCONNECTELE *pConnectEle;
+ NTSTATUS status;
+ ULONG PduSize;
+ ULONG ToCopy;
+ PVOID pIndicateBuffer;
+ ULONG Taken;
+
+ //
+ // there is data in the indicate buffer and we got a new
+ // indication, so copy some or all of the indication to the
+ // indicate buffer
+ //
+ PVOID pDest;
+ ULONG RemainPdu;
+ ULONG SpaceLeft;
+ ULONG TotalBytes;
+ ULONG ToCopy1=0;
+
+ INCR_COUNT(R3);
+ PUSH_LOCATION(0xe);
+ pConnectEle = pLowerConn->pUpperConnection;
+ ASSERT(pLowerConn->StateRcv == INDICATE_BUFFER);
+ //
+ // The indicate buffer always starts with a pdu
+ //
+ pIndicateBuffer = MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl);
+
+ // the location to start copying the new data into is right
+ // after the existing data in the buffer
+ //
+ pDest = (PVOID)((PUCHAR)pIndicateBuffer + pLowerConn->BytesInIndicate);
+
+ //
+ // the session header may not be all into the indicate
+ // buffer yet, so check that before getting the pdu length.
+ //
+ if (pLowerConn->BytesInIndicate < sizeof(tSESSIONHDR))
+ {
+ PUSH_LOCATION(0xe);
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Too Few in Indicate Buff, Adding InIndicate %X\n",
+ pLowerConn->BytesInIndicate));
+
+ ToCopy1 = sizeof(tSESSIONHDR) - pLowerConn->BytesInIndicate;
+ if (ToCopy1 > BytesIndicated)
+ {
+ ToCopy1 = BytesIndicated;
+ }
+ CTEMemCopy(pDest,pTsdu,ToCopy1);
+
+ pDest = (PVOID)((PUCHAR)pDest + ToCopy1);
+ pTsdu = (PVOID)((PUCHAR)pTsdu + ToCopy1);
+
+ pLowerConn->BytesInIndicate += (USHORT)ToCopy1;
+
+ *BytesTaken = ToCopy1;
+ }
+
+ // now check again, and pass down an irp to get more data if necessary
+ //
+ if (pLowerConn->BytesInIndicate < sizeof(tSESSIONHDR))
+ {
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:< 4 Bytes in IndicBuff, BytesinInd= %X, BytesIndicated=%x\n",
+ pLowerConn->BytesInIndicate,BytesIndicated));
+
+ PUSH_LOCATION(0xF);
+
+ //
+ // the data left in the transport is what was Available
+ // minus what we just copied to the indicate buffer
+ //
+ pConnectEle->BytesInXport = BytesAvailable - ToCopy1;
+
+ if (pConnectEle->BytesInXport)
+ {
+ PUSH_LOCATION(0x10);
+ //
+ // pass the indicate buffer down to get some more data
+ // to fill out to the end of the session hdr
+ //
+ NtBuildIndicateForReceive(pLowerConn,
+ sizeof(tSESSIONHDR)-pLowerConn->BytesInIndicate,
+ (PVOID *)ppIrp);
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:INDIC_BUF...need more data for hdr Avail= %X, InXport = %X\n",
+ BytesAvailable,pConnectEle->BytesInXport,pLowerConn));
+
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+ }
+
+ // if we get to here there isn't 4 bytes in the indicate buffer and
+ // there is no more data in the Transport, so just wait for the next
+ // indication.
+ //
+ return(STATUS_SUCCESS);
+ }
+
+ PduSize = myntohl(((tSESSIONHDR *)pIndicateBuffer)->UlongLength)
+ + sizeof(tSESSIONHDR);
+
+ // copy up to 132 bytes or the whole pdu to the indicate buffer
+ //
+ RemainPdu = PduSize - pLowerConn->BytesInIndicate;
+
+ SpaceLeft = NBT_INDICATE_BUFFER_SIZE - pLowerConn->BytesInIndicate;
+
+ if (RemainPdu < SpaceLeft)
+ ToCopy = RemainPdu;
+ else
+ ToCopy = SpaceLeft;
+
+ if (ToCopy > (BytesIndicated-ToCopy1))
+ {
+ ToCopy = (BytesIndicated - ToCopy1);
+ }
+
+ //
+ // Copy the indication or part of it to the indication
+ // buffer
+ //
+ CTEMemCopy(pDest,pTsdu,ToCopy);
+
+ pLowerConn->BytesInIndicate += (USHORT)ToCopy;
+
+ TotalBytes = pLowerConn->BytesInIndicate;
+
+ // the amount of data taken is the amount copied to the
+ // indicate buffer
+ //
+ *BytesTaken = ToCopy + ToCopy1;
+
+#if DBG
+ {
+ tSESSIONHDR UNALIGNED *pSessionHdr;
+ pSessionHdr = (tSESSIONHDR UNALIGNED *)pIndicateBuffer;
+ ASSERT((pSessionHdr->Type == NBT_SESSION_KEEP_ALIVE) ||
+ (pSessionHdr->Type == NBT_SESSION_MESSAGE));
+ }
+#endif
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:INDIC_BUFF, TotalBytes= %X, InIndic=%X, Copied(0/1)= %X %X Avail %X\n",
+ TotalBytes,pLowerConn->BytesInIndicate,ToCopy,ToCopy1,BytesAvailable));
+
+
+ // the data left in the transport is what was Available
+ // minus what we just copied to the indicate buffer
+ //
+ pConnectEle->BytesInXport = BytesAvailable - *BytesTaken;
+
+ // now check if we have a whole pdu or 132 bytes, either way
+ // enough to indicate to the client.
+ //
+ ASSERT(TotalBytes <= NBT_INDICATE_BUFFER_SIZE);
+
+ if ((TotalBytes == NBT_INDICATE_BUFFER_SIZE) ||
+ (TotalBytes == PduSize))
+ {
+
+ status = CopyDataandIndicate(
+ ReceiveEventContext,
+ (PVOID)pLowerConn,
+ ReceiveFlags,
+ TotalBytes,
+ pConnectEle->BytesInXport + TotalBytes,
+ &Taken,
+ pIndicateBuffer,
+ (PIRP *)ppIrp);
+
+ }
+ else
+ {
+
+ // not enough data in the indicate buffer yet
+ // NOTE: *BytesTaken should be set correctly above...
+ // = ToCopy + ToCopy1;
+
+ PUSH_LOCATION(0x11);
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Not Enough data indicated(INDICBUFF state), Indicated = %X,PduSize= %X,InIndic=%X\n",
+ BytesIndicated, PduSize, pLowerConn->BytesInIndicate));
+
+
+ status = STATUS_SUCCESS;
+ }
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+PartialRcv(
+ IN PVOID ReceiveEventContext,
+ IN tLOWERCONNECTION *pLowerConn,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PVOID *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive event indication handler.
+
+ It is called when an session packet arrives from the network. It calls
+ a non OS specific routine to decide what to do. That routine passes back
+ either a RcvElement (buffer) or a client rcv handler to call.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ tCONNECTELE *pConnectEle;
+ //
+ // the data for the client may be in the indicate buffer and
+ // in this case the transport could indicate us with more data. Therefore
+ // track the number of bytes available in the transport which
+ // we will get when the client finally posts a buffer.
+ // This state could also happen on a zero length Rcv when the
+ // client does not accept the data, and later posts a rcv
+ // buffer for the zero length rcv.
+ //
+ INCR_COUNT(R4);
+ PUSH_LOCATION(0x13);
+ ASSERT(pLowerConn->StateRcv == PARTIAL_RCV);
+ pConnectEle = pLowerConn->pUpperConnection;
+
+// ASSERT(pConnectEle->BytesInXport == 0);
+#if DBG
+ if (pConnectEle->BytesInXport != 0)
+ {
+ KdPrint(("Netbt!PartialRcv: pConnectEle->BytesInXport != 0 Avail %X, InIndicate=%X,InXport %X %X\n",
+ BytesAvailable,pLowerConn->BytesInIndicate,
+ pConnectEle->BytesInXport,pLowerConn));
+ }
+#endif // DBG
+ pConnectEle->BytesInXport = BytesAvailable;
+
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Got Indicated while in PartialRcv state Avail %X, InIndicate=%X,InXport %X %X\n",
+ BytesAvailable,pLowerConn->BytesInIndicate,
+ pConnectEle->BytesInXport,pLowerConn));
+
+ *BytesTaken = 0;
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiReceiveHandler (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PIRP *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive event indication handler.
+
+ It is called when an session packet arrives from the network. It calls
+ a non OS specific routine to decide what to do. That routine passes back
+ either a RcvElement (buffer) or a client rcv handler to call.
+
+Arguments:
+
+ IN PVOID ReceiveEventContext - Context provided for this event when event set
+ IN PVOID ConnectionContext - Connection Context, (pLowerConnection)
+ IN USHORT ReceiveFlags - Flags describing the message
+ IN ULONG BytesIndicated - Number of bytes available at indication time
+ IN ULONG BytesAvailable - Number of bytes available to receive
+ OUT PULONG BytesTaken - Number of bytes consumed by redirector.
+ IN PVOID pTsdu - Data from remote machine.
+ OUT PIRP *ppIrp - I/O request packet filled in if received data
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ register tLOWERCONNECTION *pLowerConn;
+ PIRP pIrp;
+ CTELockHandle OldIrq;
+ NTSTATUS status;
+ tCONNECTELE *pConnEle;
+ ULONG BTaken;
+
+ *ppIrp = NULL;
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+
+ // NOTE:
+ // Access is synchronized through the spin lock on pLowerConn for all
+ // Session related stuff. This includes the case where the client
+ // posts another Rcv Buffer in NTReceive. - so there is no need to get the
+ // pConnEle Spin lock too.
+ //
+
+ CTESpinLock(pLowerConn,OldIrq);
+// pLowerConn->InRcvHandler = TRUE;
+ pLowerConn->RefCount++;
+
+ // save this on the stack in case we need to dereference it below.
+ pConnEle = pLowerConn->pUpperConnection;
+
+ // call the correct routine depending on the state of the connection
+ // Normal/FillIrp/PartialRcv/IndicateBuffer/Inbound/OutBound
+ //
+ if ((pLowerConn->State == NBT_SESSION_UP) &&
+ (pLowerConn->StateRcv == FILL_IRP))
+ {
+ PIO_STACK_LOCATION pIrpSp;
+ PMDL pNewMdl;
+ PFILE_OBJECT pFileObject;
+ ULONG RemainingPdu;
+ PVOID NewAddress;
+ PTDI_REQUEST_KERNEL_RECEIVE pClientParams;
+ PTDI_REQUEST_KERNEL_RECEIVE pParams;
+ KIRQL OldIrq2;
+ ULONG RcvLength;
+
+
+ PUSH_LOCATION(0xa);
+ // we are still waiting for the rest of the session pdu so
+ // do not call the RcvHandlrNotOs, since we already have the buffer
+ // to put this data in.
+ // too much data may have arrived... i.e. part of the next session pdu..
+ // so check and set the receive length accordingly
+ //
+ RemainingPdu = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
+ RcvLength = RemainingPdu;
+ //
+ // try high runner case first
+ //
+ if (BytesAvailable <= RemainingPdu)
+ {
+ PUSH_LOCATION(0xb);
+ //
+ // if the client buffer is too small to take all of the rest of the
+ // data, shorten the receive length and keep track of how many
+ // bytes are left in the transport. ReceiveIndicated should have
+ // been set when the irp was passed down originally.
+ //
+ if (BytesAvailable > pConnEle->FreeBytesInMdl)
+ {
+
+ PUSH_LOCATION(0xb);
+
+ RcvLength = pConnEle->FreeBytesInMdl;
+ pConnEle->BytesInXport = BytesAvailable - RcvLength;
+ }
+ }
+ else
+ {
+ //
+ // start of session pdu in the middle of the indication
+ //
+ PUSH_LOCATION(0xc);
+ //
+ // It is possible that the client buffer is too short, so check
+ // for that case.
+ //
+ if (RemainingPdu > pConnEle->FreeBytesInMdl)
+ {
+ RcvLength = pConnEle->FreeBytesInMdl;
+ PUSH_LOCATION(0xd);
+ }
+ /* Remember how much data is left in the transport
+ when this irp passes through the completionrcv routine
+ it will pass the indication buffer back to the transport
+ to get at least 4 bytes of header information so we
+ can determine the next session pdu's size before receiving
+ it. The trick is to avoid having more than one session
+ pdu in the buffer at once.
+ */
+ pConnEle->BytesInXport = BytesAvailable - RcvLength;
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:End of FILL_IRP, found new Pdu BytesInXport=%X\n",
+ pConnEle->BytesInXport));
+
+
+ }
+
+ pIrp = pConnEle->pIrpRcv;
+
+ // if the transport has all of the data it says is available, then
+ // do the copy here ( if the client buffer is large enough - checked
+ // by !ReceiveIndicated)
+ //
+ if ((BytesAvailable == BytesIndicated) &&
+ (RcvLength >= BytesIndicated) &&
+ !pConnEle->ReceiveIndicated)
+ {
+ ULONG BytesCopied;
+ ULONG TotalBytes;
+
+ PUSH_LOCATION(0x70);
+
+ if (RcvLength > BytesIndicated)
+ RcvLength = BytesIndicated;
+
+ status = TdiCopyBufferToMdl(
+ pTsdu,
+ 0,
+ RcvLength,
+ pConnEle->pNextMdl,
+ pConnEle->OffsetFromStart,
+ &BytesCopied);
+
+ //
+ // if the irp is not yet full, or the free bytes have not
+ // been exhausted by this copy, then adjust some counts and return
+ // quickly, otherwise call the completion rcv routine as if the
+ // irp has completed normally from the transport -
+ //
+ TotalBytes = pConnEle->BytesRcvd + BytesCopied;
+
+ if ((TotalBytes < pConnEle->TotalPcktLen) &&
+ (BytesCopied < pConnEle->FreeBytesInMdl))
+ {
+ PMDL pMdl;
+
+ //
+ // take the short cut and do not call completion rcv since we
+ // are still waiting for more data
+ //
+ PUSH_LOCATION(0x81);
+ pConnEle->BytesRcvd += BytesCopied;
+ pConnEle->FreeBytesInMdl -= BytesCopied;
+
+ // clean up the partial mdl.
+ //
+ pMdl = pConnEle->pNewMdl;
+ MmPrepareMdlForReuse(pMdl);
+
+ // set where the next rcvd data will start, by setting the pNextMdl and
+ // offset from start.
+ //
+ pMdl = pConnEle->pNextMdl;
+ if ((BytesCopied + pConnEle->OffsetFromStart) < MmGetMdlByteCount(pMdl))
+ {
+ PUSH_LOCATION(0x82);
+ //
+ // All of this data will fit into the current Mdl, and
+ // the next data will start in the same Mdl (if there is more data)
+ //
+ pConnEle->OffsetFromStart += BytesCopied;
+ }
+ else
+ {
+ PUSH_LOCATION(0x83)
+ SumMdlLengths(pMdl,
+ pConnEle->OffsetFromStart + BytesCopied,
+ pConnEle);
+ }
+ *BytesTaken = BytesCopied;
+ status = STATUS_SUCCESS;
+
+ IF_DBG(NBT_DEBUG_FASTPATH)
+ KdPrint(("I"));
+ goto ExitRoutine;
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_FASTPATH)
+ KdPrint(("i"));
+ CTESpinFree(pLowerConn,OldIrq);
+ //
+ // the values are set to this so that when Completion Rcv is
+ // called it will increment the BytesRcvd by BytesCopied.
+ //
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+ pIrp->IoStatus.Information = BytesCopied;
+
+ //
+ // now call the irp completion routine, shorting out the io
+ // subsystem - to process the irp
+ //
+ status = CompletionRcv(NULL,pIrp,(PVOID)pLowerConn);
+ //
+ // complete the irp back to the client if required
+ //
+ if (status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ IoAcquireCancelSpinLock(&OldIrq2);
+ IoSetCancelRoutine(pIrp,NULL);
+ IoReleaseCancelSpinLock(OldIrq2);
+
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+ }
+ }
+ //
+ // tell the transport we took all the data that we did take.
+ // Since CompletionRcv has unlocked the spin lock and decremented
+ // the refcount, return here.
+ //
+ *BytesTaken = BytesCopied;
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ //
+ // Either BytesIndicated != BytesAvailable or the RcvBuffer
+ // is too short, so make up an Irp with a partial Mdl and pass it
+ // to the transport.
+ //
+ PUSH_LOCATION(0x71);
+
+ NewAddress = (PVOID)((PCHAR)MmGetMdlVirtualAddress(pConnEle->pNextMdl)
+ + pConnEle->OffsetFromStart);
+
+ /* create a partial MDL so that the new data is copied after the existing data
+ in the MDL. Use the pNextMdl field stored in the pConnEle
+ that was set up during the last receive.( since at that time
+ we knew the BytesAvailable then). Without this we would have to
+ traverse the list of Mdls for each receive.
+
+ 0 for length means map the rest of the buffer
+ */
+ pNewMdl = pConnEle->pNewMdl;
+
+ IoBuildPartialMdl(pConnEle->pNextMdl,pNewMdl,NewAddress,0);
+ //
+ // hook the new partial mdl to the front of the MDL chain
+ //
+ pNewMdl->Next = pConnEle->pNextMdl->Next;
+
+ pIrp->MdlAddress = pNewMdl;
+ ASSERT(pNewMdl);
+
+ CHECK_PTR(pConnEle);
+ pConnEle->pIrpRcv = NULL;
+
+ IoAcquireCancelSpinLock(&OldIrq2);
+ IoSetCancelRoutine(pIrp,NULL);
+ IoReleaseCancelSpinLock(OldIrq2);
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ pClientParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
+
+ /* this code is sped up somewhat by expanding the code here rather than calling
+ the TdiBuildReceive macro
+
+ make the next stack location the current one. Normally IoCallDriver
+ would do this but we are not going through IoCallDriver here, since the
+ Irp is just passed back with RcvIndication.
+ */
+ ASSERT(pIrp->CurrentLocation > 1);
+ IoSetNextIrpStackLocation(pIrp);
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
+
+ pIrpSp->CompletionRoutine = CompletionRcv;
+
+ pParams->ReceiveLength = RcvLength;
+
+ pIrpSp->CompletionRoutine = CompletionRcv;
+ pIrpSp->Context = (PVOID)pLowerConn;
+
+ /* set flags so the completion routine is always invoked.
+ */
+ pIrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
+
+ pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ pIrpSp->MinorFunction = TDI_RECEIVE;
+
+ pFileObject = pLowerConn->pFileObject;
+ pIrpSp->FileObject = pFileObject;
+ pIrpSp->DeviceObject = IoGetRelatedDeviceObject(pFileObject);
+
+ pParams->ReceiveFlags = pClientParams->ReceiveFlags;
+
+ /*
+ pass the Irp back to the transport
+ */
+ *ppIrp = (PVOID)pIrp;
+ *BytesTaken = 0;
+
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+
+ }
+ else
+ if ((pLowerConn->State == NBT_SESSION_UP) &&
+ (pLowerConn->StateRcv == NORMAL))
+ {
+ ULONG PduSize;
+ UCHAR Passit;
+
+ INCR_COUNT(R1);
+ /*
+ check indication and if less than 1 pdu or 132 bytes then
+ copy to the indicate buffer and go to Indic_buffer state
+ The while loop allows us to indicate multiple Pdus to the
+ client in the event that several indications arrive in one
+ indication from the transport
+ NOTE:
+ It is possible to get an indication that occurs in the middle
+ of the pdu if the client took the first indication rather
+ than passing an irp back, and thence going to the FILL_IRP
+ state. So check if BytesRcvd is zero, meaning that we are
+ expecting a new PDU.
+ */
+ ASSERT(pConnEle->BytesInXport == 0);
+ ASSERT(pLowerConn->StateRcv == NORMAL);
+
+ if (pConnEle->BytesRcvd == 0)
+ {
+ if (BytesIndicated >= sizeof(tSESSIONHDR))
+ {
+ PduSize = myntohl(((tSESSIONHDR UNALIGNED *)pTsdu)->UlongLength)
+ + sizeof(tSESSIONHDR);
+ Passit = FALSE;
+
+ }
+ else
+ {
+ status = LessThan4BytesRcvd(pLowerConn,
+ BytesAvailable,
+ BytesTaken,
+ ppIrp);
+ goto ExitRoutine;
+ }
+
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Got rest of PDU in indication BytesInd %X, BytesAvail %X\n",
+ BytesIndicated, BytesAvailable));
+
+ /* This is the remaining pdu size
+ */
+ PduSize = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
+ /* a flag to pass the if below, since we are passing the
+ remaining data of a pdu to the client and we do not have
+ to adhere to the 128 bytes restriction.
+ */
+ PUSH_LOCATION(0x1);
+ if (pConnEle->JunkMsgFlag)
+ {
+ //
+ // in this case the client has indicated that it took the
+ // entire message on the previous indication, so don't
+ // indicate any more to it.
+ //
+ PUSH_LOCATION(0x1);
+
+ if (BytesAvailable < PduSize)
+ {
+ BTaken = BytesAvailable;
+ }
+ else
+ {
+ BTaken = PduSize;
+ }
+ pConnEle->BytesRcvd += BTaken;
+ if (pConnEle->BytesRcvd == pConnEle->TotalPcktLen)
+ {
+ PUSH_LOCATION(0x1);
+ pConnEle->BytesRcvd = 0; // reset for the next session pdu
+ pConnEle->JunkMsgFlag = FALSE;
+ }
+ status = STATUS_SUCCESS;
+ goto SkipIndication;
+ }
+ Passit = TRUE;
+
+ }
+ /*
+ be sure that there is at least 132 bytes or a whole pdu
+ Since a keep alive has a zero length byte, we check for
+ that because the 4 byte session hdr is added to the 0 length
+ giving 4, so a 4 byte Keep Alive pdu will pass this test.
+ */
+ if ((BytesIndicated >= NBT_INDICATE_BUFFER_SIZE) ||
+ (BytesIndicated >= PduSize) || Passit )
+ {
+
+ PUSH_LOCATION(0x2);
+
+ /*
+ // Indicate to the client
+ */
+ status = RcvHandlrNotOs(
+ ReceiveEventContext,
+ (PVOID)pLowerConn,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ &BTaken,
+ pTsdu,
+ (PVOID)&pIrp
+ );
+
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ ULONG RemainingPdu;
+ PIO_STACK_LOCATION pIrpSp;
+ PTDI_REQUEST_KERNEL_RECEIVE pClientParams;
+
+ RemainingPdu = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pClientParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
+
+ // check if we can copy to the client's irp directly - meaning
+ // that we have received the whole pdu in this indication and
+ // the client's buffer is large enough, and there is no more
+ // data in the transport.
+ //
+
+ if ((RemainingPdu == (BytesIndicated - BTaken)) &&
+ (BytesIndicated == BytesAvailable) &&
+ (pClientParams->ReceiveLength >= RemainingPdu) &&
+ pIrp->MdlAddress)
+ {
+ ULONG BytesCopied;
+
+ PUSH_LOCATION(0x88);
+
+ status = TdiCopyBufferToMdl(
+ (PVOID)((PUCHAR)pTsdu + BTaken),
+ 0,
+ RemainingPdu,
+ pIrp->MdlAddress,
+ 0,
+ &BytesCopied);
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Copy to client Buffer RcvLen=%X,StateRcv=%X\n",
+ RemainingPdu,pLowerConn->StateRcv));
+
+ pIrp->IoStatus.Information = BytesCopied;
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+
+ // reset a few things since this pdu has been fully recv'd
+ //
+ CHECK_PTR(pConnEle);
+ pConnEle->BytesRcvd = 0;
+ CHECK_PTR(pConnEle);
+ pConnEle->pIrpRcv = NULL;
+
+ //
+ // tell the transport we took all the data that we did take.
+ //
+ *BytesTaken = BytesCopied + BTaken;
+
+ //
+ // complete the irp back to the client if required
+ //
+ IF_DBG(NBT_DEBUG_FASTPATH)
+ KdPrint(("F"));
+
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ pLowerConn->BytesRcvd += BytesCopied;
+
+ DerefLowerConnFast(pLowerConn,pConnEle,OldIrq);
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+ PUSH_LOCATION(0x3);
+
+ status = ProcessIrp(pLowerConn,
+ pIrp,
+ pTsdu,
+ &BTaken,
+ BytesIndicated,
+ BytesAvailable);
+
+ *BytesTaken = BTaken;
+ ASSERT(*BytesTaken <= (pConnEle->TotalPcktLen + sizeof(tSESSIONHDR)) );
+ if (status == STATUS_RECEIVE_EXPEDITED)
+ {
+ // in this case the processirp routine has completed the
+ // irp, so just return since the completion routine will
+ // have adjusted the RefCount and InRcvHandler flag
+ //
+ *ppIrp = NULL;
+ CTESpinFree(pLowerConn,OldIrq);
+ return(STATUS_SUCCESS);
+ }
+ else
+ if (status == STATUS_SUCCESS)
+ {
+ *ppIrp = NULL;
+
+ }
+ else
+ {
+ *ppIrp = (PVOID)pIrp;
+ }
+ }
+
+
+ }
+ else
+ {
+ // for the skip indication case the client has told us it
+ // does not want to be indicated with any more of the data
+ //
+ SkipIndication:
+ //
+ // the client received some, all or none of the data
+ // For Keep Alives the PduSize is 4 and BytesTaken = 4
+ // so this check and return status success
+ //
+ *BytesTaken = BTaken;
+
+ pLowerConn->BytesRcvd += BTaken - sizeof(tSESSIONHDR);
+
+ //
+ // if the connection has disonnected, then just return
+ //
+ if (!pLowerConn->pUpperConnection)
+ {
+ *BytesTaken = BytesAvailable;
+ status = STATUS_SUCCESS;
+ }
+ else
+ if (BTaken > BytesAvailable)
+ {
+ //
+ // in this case the client has taken all of the message
+ // which could be larger than the available because
+ // we set bytesavail to the message length. So set a flag
+ // that tells us to discard the rest of the message as
+ // it comes in.
+ //
+ pConnEle->JunkMsgFlag = TRUE;
+ pConnEle->BytesRcvd = BytesAvailable - sizeof(tSESSIONHDR);
+ *BytesTaken = BytesAvailable;
+
+ }
+ else
+ if (pLowerConn->StateRcv == PARTIAL_RCV)
+ {
+ // this may be a zero length send -that the client has
+ // decided not to accept. If so then the state will be set
+ // to PartialRcv. In this case do NOT go down to the transport
+ // and get the rest of the data, but wait for the client
+ // to post a rcv buffer.
+ //
+
+ // amount left in the transport...
+ pConnEle->BytesInXport = BytesAvailable - BTaken;
+ status = STATUS_SUCCESS;
+ }
+ else
+ if (BTaken == PduSize)
+ {
+ /*
+ Must have taken all of the pdu data, so check for
+ more data available - if so send down the indicate
+ buffer to get it.
+ */
+ ASSERT(BTaken <= BytesIndicated);
+ if (BytesAvailable <= BTaken)
+ {
+ /* FAST PATH
+ */
+ PUSH_LOCATION(0x8);
+
+ status = STATUS_SUCCESS;
+
+ }
+ else
+ {
+ /*
+ get remaining data with the indicate buffer
+ */
+ status = MoreDataRcvdThanNeeded(pLowerConn,
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ pTsdu,
+ ppIrp);
+ }
+ }
+ else
+ {
+ //
+ // the client may have taken all the data in the
+ // indication!!, in which case return status success
+ // Note: that we check bytes available here not bytes
+ // indicated - since the client could take all indicated
+ // data but still leave data in the transport.
+ //
+ if (BTaken == BytesAvailable)
+ {
+ PUSH_LOCATION(0x4);
+ status = STATUS_SUCCESS;
+
+ }
+ else
+ {
+ PUSH_LOCATION(0x87);
+ if (BTaken > PduSize)
+ {
+#ifndef VXD
+#if DBG
+ DbgBreakPoint();
+#endif
+#endif
+ //
+ // the client took more than a PDU size worth,
+ // which is odd....
+ //
+ PUSH_LOCATION(0x87);
+ ASSERT(BTaken <= PduSize);
+
+ CTESpinFreeAtDpc(pLowerConn);
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLockAtDpc(pLowerConn);
+
+ status = STATUS_SUCCESS;
+
+ }
+ else
+ {
+ //
+ // otherwise the client did not take all of the data,
+ // which can mean that
+ // the client did not take all that it could, so
+ // go to the partial rcv state to keep track of it.
+ //
+ status = ClientTookSomeOfTheData(pLowerConn,
+ BytesIndicated,
+ BytesAvailable,
+ *BytesTaken,
+ PduSize);
+ }
+ }
+ }
+
+ }
+
+ }
+ else
+ {
+ status = NotEnoughDataYet(pLowerConn,
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ PduSize,
+ (PVOID *)ppIrp);
+ }
+ }
+ else
+ {
+ status = (*pLowerConn->CurrentStateProc)(ReceiveEventContext,
+ pLowerConn,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ pTsdu,
+ ppIrp);
+ }
+
+ //
+ // in the IndicateBuffer state we have sent the indicate buffer
+ // down the the transport and expect it to come back in
+ // NewSessionCompletionRoutine. Therefore do not dereference the lower
+ // connection and do not change the InRcvHandler flag.
+
+ // If an Irp
+ // is returned, then do not undo the reference - but rather
+ // wait for CompletionRcv to be called.
+ //
+ExitRoutine:
+ if (status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ //
+ // quickly check if we can just decrement the ref count without calling
+ // nbtDereferenceConnection
+ //
+ PUSH_LOCATION(0x50);
+ DerefLowerConnFast(pLowerConn,pConnEle,OldIrq);
+ }
+ else
+ CTESpinFree(pLowerConn,OldIrq);
+
+
+ return(status);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+ProcessIrp(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN PIRP pIrp,
+ IN PVOID pBuffer,
+ IN PULONG BytesTaken,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable
+ )
+/*++
+
+Routine Description:
+
+ This routine handles a Receive Irp that the client has returned on an
+ indication. The idea here is to check the Irp's MDL length to be
+ sure the pdu fits into the MDL, and also keep track of the situation where
+ more than one data is required to fill the pdu.
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation (success or an exception).
+
+--*/
+{
+ NTSTATUS status;
+ PTDI_REQUEST_KERNEL_RECEIVE pParams;
+ PIO_STACK_LOCATION pIrpSp;
+ tCONNECTELE *pConnectEle;
+ PTDI_REQUEST_KERNEL_RECEIVE pClientParams;
+ ULONG RemainingPdu;
+ PMDL pMdl;
+ PFILE_OBJECT pFileObject;
+ ULONG ReceiveLength;
+ BOOLEAN QuickRoute;
+ BOOLEAN FromCopyData;
+
+ pConnectEle = pLowerConn->pUpperConnection;
+
+ status = STATUS_SUCCESS;
+
+ // subtract session header and any bytes that the client took
+ //
+ BytesAvailable -= *BytesTaken;
+
+ //
+ // put together an Irp stack location to process the receive and pass down
+ // to the transport.
+ //
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pClientParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
+
+ //
+ // check if this will be a multiple rcv session pdu. If it is then
+ // allocate a partial MDL to be used for mapping part of the first
+ // MDL in each chunk received
+ //
+ RemainingPdu = pConnectEle->TotalPcktLen - pConnectEle->BytesRcvd;
+ ReceiveLength = RemainingPdu;
+ PUSH_LOCATION(0x19);
+ pIrpSp = IoGetNextIrpStackLocation(pIrp);
+
+ // this code should not be hit if called by CopyDataandIndicate
+ // which is in the indicate buffer state since it adjusts the bytesInXport
+ // which is also set by the code in TdiReceiveHndlr in the INDICATE_BUFFER
+ // state before calling CopyDataandIndicate. Also, CopyDataandIndicate
+ // does not want this routine to set the state to fillIrp when Bytes
+ // Available < RemainingPdu
+ //
+ FromCopyData = (pLowerConn->StateRcv == INDICATE_BUFFER);
+ if (!FromCopyData)
+ {
+
+ QuickRoute = TRUE;
+ // we need this code within the check since this routine is also called by the
+ // HandleNewSessionPdu routine, which calls IoCallDriver, which
+ // increments the stack location itself.
+ //
+ ASSERT(pIrp->CurrentLocation > 1);
+
+ if (BytesAvailable == RemainingPdu)
+ {
+ if (pClientParams->ReceiveLength >= BytesAvailable)
+ {
+ // *** FAST PATH CASE ****
+ goto ExitCode;
+ }
+ }
+ else
+ if (BytesAvailable < RemainingPdu ) // need more data from transport
+ {
+ PUSH_LOCATION(0x14);
+ // it is possible for the client to pass down an irp with no
+ // MDL in it, so we check for that here
+ //
+ if (pIrp->MdlAddress)
+ {
+ PUSH_LOCATION(0x14);
+
+ //
+ // save the client's irp address since the session pdu will arrive
+ // in several chunks, and we need to continually pass the irp to the
+ // transport for each chunk.
+ //
+ //pConnectEle->pIrpRcv = pIrp;
+ // NOTE: the pIrp is NOT saved here because the irp is about
+ // to be passed back to the transport. Hence we do not want
+ // to accidently complete it in DisconnectHandlrNotOs
+ // if a disconnect comes in while the irp is in the transport.
+ // pIrpRcv is set to pIrp in Completion Rcv while we have
+ // the irp in our possession.
+
+ //
+ // keep the initial Mdl(chain) since we need to
+ // to copy new data after the existing data, when the session pdu arrives
+ // as several chunks from TCP. Keeping the Mdl around allows us to
+ // reconstruct the original Mdl chain when we are all done.
+ //
+ pLowerConn->pMdl = pIrp->MdlAddress;
+ //
+ // this call maps the client's Mdl so that on each partial Mdl creation
+ // we don't go through a mapping and unmapping (when MmPrepareMdlForReuse)
+ // is called in the completion routine.
+ //
+ (PVOID)MmGetSystemAddressForMdl(pIrp->MdlAddress);
+
+ pMdl = pIrp->MdlAddress;
+
+ // the nextmdl is setup to allow us to create a partial Mdl starting
+ // from the next one. CompletionRcv will adjust this if it needs to.
+ //
+ pConnectEle->pNextMdl = pMdl;
+
+ // need more data from the transport to fill this
+ // irp
+ //
+ CHECK_PTR(pConnectEle);
+ pConnectEle->pIrpRcv = NULL;
+ pLowerConn->StateRcv = FILL_IRP;
+ pLowerConn->CurrentStateProc = FillIrp;
+ }
+
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ // if the client buffer is big enough, increment to the next
+ // io stack location and jump to the code that sets up the
+ // irp, since we always want to pass it to the transport in this
+ // case because the transport will hold onto the irp till it is full
+ // if it can. (faster)
+ //
+ if (pClientParams->ReceiveLength >= RemainingPdu)
+ {
+ // *** FAST PATH CASE ****
+ IoSetNextIrpStackLocation(pIrp);
+ pConnectEle->FreeBytesInMdl = ReceiveLength;
+ pConnectEle->CurrentRcvLen = RemainingPdu;
+ goto ExitCode2;
+ }
+
+ //
+ // if there is no mdl then we want to be able to go through the
+ // quick route below to return the null mdl right away, so
+ // don't set Quickroute false here.
+ //
+
+
+ }
+ else
+ if (BytesAvailable > RemainingPdu)
+ {
+ PUSH_LOCATION(0x15);
+ //
+ // there is too much data, so keep track of the
+ // fact that there is data left in the transport
+ // and get it when the irp completes through
+ // completion recv.
+ //
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+ pLowerConn->CurrentStateProc = IndicateBuffer;
+
+ // this calculation may have to be adjusted below if the client's
+ // buffer is too short. NOTE: BytesTaken have already been subtracted
+ // from BytesAvailable (above).
+ //
+ pConnectEle->BytesInXport = BytesAvailable - RemainingPdu;
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Switching to Indicate Buff(Irp), Indic = %X, Pdusize=%X\n",
+ BytesIndicated,pConnectEle->TotalPcktLen));
+
+
+ status = STATUS_DATA_NOT_ACCEPTED;
+ }
+
+ // DEBUG*
+ //IoSetNextIrpStackLocation(pIrp);
+ }
+ else
+ {
+ QuickRoute = FALSE;
+ }
+
+ //
+ // if the receive buffer is too short then flag it so when the client
+ // passes another buffer to NBT, nbt will pass it to the transport
+ //
+ //if (BytesAvailable > pClientParams->ReceiveLength )
+ {
+
+ // so just check for too short of a client buffer.
+ //
+ if (RemainingPdu > pClientParams->ReceiveLength)
+ {
+ PUSH_LOCATION(0x17);
+
+ ReceiveLength = pClientParams->ReceiveLength;
+ //
+ // Adjust the number of bytes left in the transport up by the number of
+ // bytes not taken by the client. Be sure not to add in the number
+ // of bytes in the transport twice, since it could have been done
+ // above where the state is set to INDICATE_BUFFER
+ //
+ if (status == STATUS_DATA_NOT_ACCEPTED)
+ {
+ // BytesInXport was already incremented to account for any
+ // amount over remainingPdu, so just add the amount that the
+ // client buffer is short of RemainingPdu
+ //
+ PUSH_LOCATION(0x18);
+ if (BytesAvailable > ReceiveLength )
+ {
+ pConnectEle->BytesInXport += (RemainingPdu - ReceiveLength);
+ }
+ // the client has not taken all of the data , but has returned
+ // a buffer that is ReceiveLength long, therefore the amount
+ // that the client needs to take is just the total pdu - rcvlength.
+ //
+ pConnectEle->ReceiveIndicated = (RemainingPdu -
+ ReceiveLength);
+ }
+ else
+ {
+ //
+ // BytesInXport has not been incremented yet so add the entire
+ // amount that the client buffer is too short by. Check if
+ // the client's buffer will take all of the data.
+ //
+ if (BytesAvailable > ReceiveLength )
+ {
+ pConnectEle->BytesInXport += (BytesAvailable - ReceiveLength);
+ }
+ // the client has not taken all of the data , but has returned
+ // a buffer that is ReceiveLength long, therefore the amount
+ // that the client needs to take is just what was indicated
+ // to the client - recvlength.
+ //
+ pConnectEle->ReceiveIndicated = (RemainingPdu -
+ ReceiveLength);
+
+ }
+
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Switching to PartialRcv for Irp. RecvInd. =%X, RemainPdu %X Avail %X\n",
+ pConnectEle->ReceiveIndicated,RemainingPdu,BytesAvailable));
+ }
+
+ }
+
+ExitCode:
+
+ // keep track of data in MDL so we know when it is full and we need to
+ // return it to the user. CurrentRcvLen tells us how many bytes the current
+ // Irp can have max when the Mdl is full.
+ //
+ pConnectEle->FreeBytesInMdl = ReceiveLength;
+ pConnectEle->CurrentRcvLen = ReceiveLength;
+ if (ReceiveLength > RemainingPdu)
+ {
+ pConnectEle->CurrentRcvLen = RemainingPdu;
+ }
+ if (QuickRoute)
+ {
+ //
+ // check if we can copy the data to the client's MDL
+ // right here. If the indication is too short pass an Irp down
+ // to the transport.
+ //
+ BytesIndicated -= *BytesTaken;
+
+ if ((ReceiveLength <= BytesIndicated))
+ {
+ ULONG BytesCopied;
+
+ PUSH_LOCATION(0x76);
+
+ if (pIrp->MdlAddress)
+ {
+
+ status = TdiCopyBufferToMdl(
+ (PVOID)((PUCHAR)pBuffer + *BytesTaken),
+ 0,
+ ReceiveLength,
+ pIrp->MdlAddress,
+ 0,
+ &BytesCopied);
+
+ }
+ else
+ {
+ //
+ // No Mdl, so just return the irp to the client, and then
+ // return success to the caller so we tell the transport that
+ // we took only BytesTaken
+ //
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:No MDL, so complete Irp\n"));
+
+
+ PUSH_LOCATION(0x77);
+ BytesCopied = 0;
+ }
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Copy to client Buffer RcvLen=%X,StateRcv=%X\n",
+ ReceiveLength,pLowerConn->StateRcv));
+
+ pIrp->IoStatus.Information = BytesCopied;
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+ //
+ // now call the irp completion routine, shorting out the io
+ // subsystem - to process the irp
+ //
+ CTESpinFreeAtDpc(pLowerConn);
+ status = CompletionRcv(NULL,pIrp,(PVOID)pLowerConn);
+
+ //
+ // tell the transport we took all the data that we did take.
+ //
+ *BytesTaken += BytesCopied;
+
+ IF_DBG(NBT_DEBUG_FASTPATH)
+ KdPrint(("f"));
+ //
+ // complete the irp back to the client if required
+ //
+ if (status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ PUSH_LOCATION(0x76);
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Completing Irp Quickly\n"));
+
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ }
+
+ // since we have called CompletionRcv, that routine has
+ // adjusted the refcount and InRcvHandlr flag, so return this
+ // status to cause the caller to return directly
+ CTESpinLockAtDpc(pLowerConn);
+ return(STATUS_RECEIVE_EXPEDITED);
+
+ }
+ else
+ {
+ //
+ // make the next stack location the current one. Normally IoCallDriver
+ // would do this but we are not going through IoCallDriver here, since the
+ // Irp is just passed back with RcvIndication.
+ //
+ IoSetNextIrpStackLocation(pIrp);
+ }
+
+ }
+ExitCode2:
+ pIrpSp->CompletionRoutine = CompletionRcv;
+ pIrpSp->Context = (PVOID)pLowerConn;
+
+ // set Control flags so the completion routine is always invoked.
+ pIrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
+
+ pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ pIrpSp->MinorFunction = TDI_RECEIVE;
+
+ pFileObject = pLowerConn->pFileObject;
+ pIrpSp->FileObject = pFileObject;
+ pIrpSp->DeviceObject = IoGetRelatedDeviceObject(pFileObject);
+
+ pParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
+ pParams->ReceiveFlags = pClientParams->ReceiveFlags;
+
+ // Set the correct receive length in the irp in case the client has
+ // passed one down that is larger than the message
+ //
+ pParams->ReceiveLength = ReceiveLength;
+
+ //
+ // just check for a zero length send, where the client has
+ // passed down an Irp with a null mdl, or the pdu size is zero. We don't want to pass
+ // that to the transport because it will hold onto it till the next
+ // pdu comes in from the wire - we want to complete the irp when this routine
+ // returns. When this is called from CopyDataAndIndicate don't
+ // to this because copydataandindicate does all the checks.
+ //
+ if (!FromCopyData)
+ {
+ if ((RemainingPdu == 0) || !pIrp->MdlAddress)
+ {
+ //
+ // the call to IoCompleteRequest will call completionRcv which will
+ // decrement the RefCount. Similarly returning status success will
+ // cause the caller to decrement the ref count, so increment one
+ // more time here to account for this second decrement.
+ //
+ pLowerConn->RefCount++;
+ CTESpinFreeAtDpc(pLowerConn);
+
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ CTESpinLockAtDpc(pLowerConn);
+
+ status = STATUS_SUCCESS;
+ }
+ else
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ return(status);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+ClientBufferOverFlow(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tCONNECTELE *pConnEle,
+ IN PIRP pIrp,
+ IN ULONG BytesRcvd
+ )
+/*++
+
+Routine Description:
+
+ This routine completes the Irp by tracking the number of bytes received
+
+Arguments:
+
+ DeviceObject - unused.
+
+ Irp - Supplies Irp that the transport has finished processing.
+
+ Context - Supplies the pLowerConn - the connection data structure
+
+Return Value:
+
+ The final status from the operation (success or an exception).
+
+--*/
+{
+
+ // *TODO*
+
+// ASSERT(0);
+
+ switch (pLowerConn->StateRcv)
+ {
+ case PARTIAL_RCV:
+
+
+ case FILL_IRP:
+
+
+ case NORMAL:
+
+
+
+ case INDICATE_BUFFER:
+
+
+ default:
+ ;
+ }
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+CompletionRcv(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This routine completes the Irp by tracking the number of bytes received
+
+Arguments:
+
+ DeviceObject - unused.
+
+ Irp - Supplies Irp that the transport has finished processing.
+
+ Context - Supplies the pLowerConn - the connection data structure
+
+Return Value:
+
+ The final status from the operation (success or an exception).
+
+--*/
+{
+ register tCONNECTELE *pConnectEle;
+ NTSTATUS status;
+ ULONG BytesRcvd;
+ tLOWERCONNECTION *pLowerConn;
+ PKDPC pDpc;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq2;
+ PMDL pMdl;
+ PIO_STACK_LOCATION pIrpSp;
+ PTDI_REQUEST_KERNEL_RECEIVE pParams;
+ BOOLEAN AllowDereference=TRUE;
+
+ //
+ // Do some checking to keep the Io system happy - propagate the pending
+ // bit up the irp stack frame.... if it was set by the driver below then
+ // it must be set by me
+ //
+ if (Irp->PendingReturned)
+ {
+ IoMarkIrpPending(Irp);
+ }
+
+ // check the bytes recvd
+ pLowerConn = (tLOWERCONNECTION *)Context;
+ //
+ // if the link has disconnected, do not process the irp, just pass it
+ // up the chain.
+ //
+ CTESpinLock(pLowerConn,OldIrq);
+ if (!NT_SUCCESS(Irp->IoStatus.Status) || !pLowerConn->pUpperConnection)
+ {
+ PUSH_LOCATION(0x1);
+ if (pLowerConn->StateRcv == FILL_IRP)
+ {
+ PUSH_LOCATION(0x1);
+ Irp->MdlAddress = pLowerConn->pMdl;
+ ASSERT(Irp->MdlAddress);
+
+ }
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+ SetStateProc(pLowerConn,RejectAnyData);
+ //
+ // the rcv failed so kill the connection since
+ // we can't keep track of message boundaries any more.
+ //
+ CTESpinFree(pLowerConn,OldIrq);
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLock(pLowerConn,OldIrq);
+
+ status = STATUS_SUCCESS;
+ goto ExitCode;
+ }
+
+ pConnectEle = pLowerConn->pUpperConnection;
+
+ // keep track of how many bytes have been received
+ //
+ BytesRcvd = Irp->IoStatus.Information;
+ pConnectEle->BytesRcvd += BytesRcvd;
+ //
+ // subtract the number of bytes rcvd from the length of the client
+ // buffer
+ // so when more data arrives we can determine if we are going to
+ // overflow the client buffer.
+ //
+ pConnectEle->FreeBytesInMdl -= BytesRcvd;
+
+ pIrpSp = IoGetCurrentIrpStackLocation(Irp);
+ pParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
+
+ pLowerConn->BytesRcvd += BytesRcvd;
+
+ CHECK_PTR(pConnectEle);
+ if (Irp->IoStatus.Status == STATUS_BUFFER_OVERFLOW)
+ {
+ //
+ // the client's buffer was too short - probably because he said it
+ // was longer than it really was
+ //
+ PUSH_LOCATION(0x1a);
+ KdPrint(("Nbt:Client Buffer Too short on CompletionRcv\n"));
+
+ if (pLowerConn->StateRcv == FILL_IRP)
+ {
+ PUSH_LOCATION(0x1a);
+ Irp->MdlAddress = pLowerConn->pMdl;
+ ASSERT(Irp->MdlAddress);
+
+
+ }
+ pConnectEle->BytesRcvd = 0; // reset for the next session pdu
+ status = ClientBufferOverFlow(pLowerConn,pConnectEle,Irp,BytesRcvd);
+
+ //
+ // the client's buffer was too short so kill the connection since
+ // we can't keep track of message boundaries any more.
+ //
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+ SetStateProc(pLowerConn,RejectAnyData);
+ CTESpinFree(pLowerConn,OldIrq);
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLock(pLowerConn,OldIrq);
+
+ goto ExitCode;
+ }
+ else
+ if ((pConnectEle->FreeBytesInMdl == 0) ||
+ (pConnectEle->BytesRcvd == pConnectEle->TotalPcktLen))
+ {
+ INCR_COUNT(C1);
+ //
+ // this case handles when the Irp MDL is full or the whole pdu has been
+ // received.
+ //
+
+ //
+ // reset the MDL fields back to where they were
+ // if this was a multi-rcv session pdu
+ //
+ //
+ if (pLowerConn->StateRcv == FILL_IRP)
+ {
+
+ INCR_COUNT(C2);
+ PUSH_LOCATION(0x1b);
+
+ Irp->MdlAddress = pLowerConn->pMdl;
+ ASSERT(Irp->MdlAddress);
+
+ //
+ // allow the MDL to be used again for the next session PDU
+ //
+ pMdl = pConnectEle->pNewMdl;
+ MmPrepareMdlForReuse(pMdl);
+
+ pConnectEle->OffsetFromStart = 0;
+
+ }
+ //
+ // The client may have passed down a too short irp which we are
+ // tracking with ReceiveIndicated, so set state to partialrcv if
+ // necessary.
+ //
+ if (pConnectEle->ReceiveIndicated == 0)
+ {
+ pLowerConn->StateRcv = NORMAL;
+ pLowerConn->CurrentStateProc = Normal;
+ }
+ else
+ {
+ PUSH_LOCATION(0x26);
+ //
+ // there may still be data left in the transport
+ //
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Short Rcv, still data indicated to client\n"));
+
+ pLowerConn->StateRcv = PARTIAL_RCV;
+ pLowerConn->CurrentStateProc = PartialRcv;
+ }
+
+ CHECK_PTR(pConnectEle);
+ pConnectEle->pIrpRcv = NULL;
+ //
+ // we have received all of the data
+ // so complete back to the client
+ //
+ status = STATUS_SUCCESS;
+ //
+ // the amount of data in this irp is the CurrentRcvLen which
+ // could be less than BytesRcvd when the client passes down
+ // short rcv buffers.
+ //
+ Irp->IoStatus.Information = pConnectEle->CurrentRcvLen;
+
+ if (pConnectEle->BytesRcvd == pConnectEle->TotalPcktLen)
+ {
+
+ pConnectEle->BytesRcvd = 0; // reset for the next session pdu
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ }
+ else
+ {
+ PUSH_LOCATION(0x27);
+ //
+ // this MDL must be too short to take the whole pdu, so set the
+ // status to buffer overflow.
+ //
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+
+ }
+
+ //
+ // Check if there is still more data in the transport or if the client
+ // has been indicated with more data and has subsequently posted a rcv
+ // which we must get now and pass to the transport.
+ //
+ if ((pConnectEle->BytesInXport) || (pLowerConn->StateRcv == PARTIAL_RCV))
+ {
+ INCR_COUNT(C3);
+ //
+ // send down another
+ // irp to get the data and complete the client's current irp.
+ //
+ PUSH_LOCATION(0x1c);
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:ComplRcv BytesInXport= %X, %X\n",pConnectEle->BytesInXport,
+ pLowerConn));
+
+ if (pLowerConn->StateRcv != PARTIAL_RCV)
+ {
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+ pLowerConn->CurrentStateProc = IndicateBuffer;
+ pLowerConn->BytesInIndicate = 0;
+ }
+
+ CTESpinFree(pLowerConn,OldIrq);
+
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine(Irp,NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+
+ // Complete the current Irp
+ IoCompleteRequest(Irp,IO_NETWORK_INCREMENT);
+
+ CTESpinLock(pLowerConn,OldIrq);
+
+ // rather than call HandleNewSessionPdu directly, we queue a
+ // Dpc since streams does not currently expect to get a recv
+ // posted while it is processing an indication response. The
+ // Dpc will run when streams is all done, and it should handle
+ // this posted receive ok.
+
+
+ if (pLowerConn->StateRcv == PARTIAL_RCV)
+ {
+ //
+ // check if the client has passed down another rcv buffer
+ // and if so, start a Dpc which will pass down the client's
+ // buffer.
+ //
+ if (!IsListEmpty(&pConnectEle->RcvHead))
+ {
+ pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('p'));
+ if (pDpc)
+ {
+ KeInitializeDpc(pDpc,
+ DpcGetRestOfIndication,
+ (PVOID)pLowerConn);
+
+ KeInsertQueueDpc(pDpc,NULL,NULL);
+ //
+ // we don't want to dereference pLowerConn at the end
+ // since we will use it in the DPC routine.
+ //
+ CTESpinFree(pLowerConn,OldIrq);
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+ }
+ else
+ {
+ CTESpinFreeAtDpc(pLowerConn);
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLockAtDpc(pLowerConn);
+ }
+
+ }
+ }
+ else
+ {
+ pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('q'));
+ if (pDpc)
+ {
+ KeInitializeDpc(pDpc,
+ DpcHandleNewSessionPdu,
+ (PVOID)pLowerConn);
+ //
+ // just get the session hdr to start with so we know how large
+ // the pdu is, then get the rest of the pdu after that completes.
+ //
+ KeInsertQueueDpc(pDpc,NULL,(PVOID)sizeof(tSESSIONHDR));
+ //
+ // we don't want to dereference pLowerConn at the end
+ // since we will use it in the DPC routine.
+ //
+ CTESpinFree(pLowerConn,OldIrq);
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+ }
+ else
+ {
+ CTESpinFreeAtDpc(pLowerConn);
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLockAtDpc(pLowerConn);
+ }
+ }
+
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+ goto ExitCode;
+ }
+ }
+ else
+ if (pConnectEle->BytesRcvd < pConnectEle->TotalPcktLen)
+ {
+ ULONG Bytes;
+
+ INCR_COUNT(C4);
+ PUSH_LOCATION(0x1d);
+ //
+ // in this case we have not received all of the data from the transport
+ // for this session pdu, so tell the io subystem not to finish processing
+ // the irp yet if it is not a partial Rcv.
+ //
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ // clean up the partial mdl.
+ //
+ pMdl = pConnectEle->pNewMdl;
+ MmPrepareMdlForReuse(pMdl);
+
+ // set where the next rcvd data will start, by setting the pNextMdl and
+ // offset from start.
+ //
+ pMdl = pConnectEle->pNextMdl;
+ ASSERT(pMdl);
+
+ Bytes = BytesRcvd + pConnectEle->OffsetFromStart;
+ if (Bytes < MmGetMdlByteCount(pMdl))
+ {
+ PUSH_LOCATION(0x74);
+ //
+ // All of this data will fit into the current Mdl, and
+ // the next data will start in the same Mdl (if there is more data)
+ //
+ pConnectEle->OffsetFromStart += BytesRcvd;
+
+ IF_DBG(NBT_DEBUG_FILLIRP)
+ KdPrint(("~"));
+ }
+ else
+ {
+ //
+ // sum the Mdl lengths until we find enough space for the data
+ // to fit into.
+ //
+ IF_DBG(NBT_DEBUG_FILLIRP)
+ KdPrint(("^"));
+ PUSH_LOCATION(0x75);
+
+ SumMdlLengths(pMdl,Bytes,pConnectEle);
+
+ }
+
+ // since we are holding on to the rcv Irp, set up a cancel routine
+ IoAcquireCancelSpinLock(&OldIrq2);
+
+ // if the session was disconnected while the transport had the
+ // irp, then cancel the irp now...
+ //
+ if ((pConnectEle->state != NBT_SESSION_UP) || Irp->Cancel)
+ {
+ CHECK_PTR(pConnectEle);
+ pConnectEle->pIrpRcv = NULL;
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+ SetStateProc(pLowerConn,RejectAnyData);
+
+
+ IoReleaseCancelSpinLock(OldIrq2);
+ CTESpinFree(pLowerConn,OldIrq);
+
+ // since the irp has been cancelled, don't touch it.
+ // return status success so the IO subsystem passes the irp
+ // back to the owner.
+ //
+ status = STATUS_SUCCESS;
+
+// Irp->IoStatus.Status = STATUS_CANCELLED;
+// IoCompleteRequest(Irp,IO_NETWORK_INCREMENT);
+
+ // the irp is being cancelled in mid session pdu. We can't
+ // recover since we have given the client only part of a pdu,
+ // therefore disconnect the connection.
+
+ OutOfRsrcKill(pLowerConn);
+
+ CTESpinLock(pLowerConn,OldIrq);
+
+ }
+ else
+ {
+ // setup the cancel routine
+ IoSetCancelRoutine(Irp,FillIrpCancelRoutine);
+
+ // the pIrpRcv value is set to Zero when the irp is in the
+ // tranport, so we can't accidently complete it twice in
+ // disconnectHandlrNotOs when a disconnect occurs and the
+ // transport has the irp. So here we save the value again so FillIrp
+ // will work correctly.
+ //
+ pConnectEle->pIrpRcv = Irp;
+ // set the irp mdl back to its original so that a cancel will
+ // find the irp in the right state
+ //
+ Irp->MdlAddress = pLowerConn->pMdl;
+
+ IoReleaseCancelSpinLock(OldIrq2);
+
+ }
+ }
+ else
+ {
+
+ //IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Too Many Bytes Rcvd!! Rcvd# = %d, TotalLen = %d,NewBytes =%d,%X\n",
+ pConnectEle->BytesRcvd,pConnectEle->TotalPcktLen,
+ Irp->IoStatus.Information,pLowerConn));
+ ASSERT(0);
+ // this status will return the irp to the user
+ //
+ status = STATUS_SUCCESS;
+ if (pLowerConn->StateRcv == FILL_IRP)
+ {
+
+ PUSH_LOCATION(0x1f);
+
+ Irp->MdlAddress = pLowerConn->pMdl;
+ Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // allow the MDL to be used again for the next session PDU
+ //
+ pMdl = pConnectEle->pNewMdl;
+ MmPrepareMdlForReuse(pMdl);
+
+
+ }
+ pConnectEle->OffsetFromStart = 0;
+ pConnectEle->BytesRcvd = 0;
+
+ pLowerConn->StateRcv = NORMAL;
+
+ //WHAT ELSE TO DO HERE OTHER THAN KILL THE CONNECTION, SINCE WE ARE
+ // PROBABLY OFF WITH RESPECT TO THE SESSION HDR....
+ // ....RESET THE CONNECTION ????
+
+ CTESpinFree(pLowerConn,OldIrq);
+
+ OutOfRsrcKill(pLowerConn);
+
+ CTESpinLock(pLowerConn,OldIrq);
+
+ }
+
+ExitCode:
+ //
+ // quickly check if we can just decrement the ref count without calling
+ // nbtDereferenceConnection - this function is __inline!!
+ //
+ PUSH_LOCATION(0x52);
+ DerefLowerConnFast(pLowerConn,pConnectEle,OldIrq);
+
+ return(status);
+
+ UNREFERENCED_PARAMETER( DeviceObject );
+}
+//----------------------------------------------------------------------------
+
+__inline
+NTSTATUS
+RcvHandlrNotOs (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PVOID *RcvBuffer
+
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive event indication handler.
+
+ It is called when an session packet arrives from the network, when the
+ session has already been established (NBT_SESSION_UP state). The routine
+ looks for a receive buffer first and failing that looks for a receive
+ indication handler to pass the message to.
+
+Arguments:
+
+ pClientEle - ptr to the connecition record for this session
+
+
+Return Value:
+
+ NTSTATUS - Status of receive operation
+
+--*/
+{
+
+ NTSTATUS status;
+ PLIST_ENTRY pRcv;
+ PVOID pRcvElement;
+ tCLIENTELE *pClientEle;
+ tSESSIONHDR UNALIGNED *pSessionHdr;
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnectEle;
+ CTELockHandle OldIrq;
+ PIRP pIrp;
+ ULONG ClientBytesTaken;
+ BOOLEAN DebugMore;
+ ULONG RemainingPdu;
+
+//********************************************************************
+//********************************************************************
+//
+// NOTE: A copy of this procedure is in Tdihndlr.c - it is inlined for
+// the NT case. Therefore, only change this procedure and then
+// copy the procedure body to Tdihndlr.c
+//
+//
+//********************************************************************
+//********************************************************************
+
+ // get the ptr to the lower connection, and from that get the ptr to the
+ // upper connection block
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+ pSessionHdr = (tSESSIONHDR UNALIGNED *)pTsdu;
+
+ //
+ // Session ** UP ** processing
+ //
+ *BytesTaken = 0;
+
+ pConnectEle = pLowerConn->pUpperConnection;
+
+ ASSERT(pConnectEle->pClientEle);
+
+ ASSERT(BytesIndicated >= sizeof(tSESSIONHDR));
+
+ // this routine can get called by the next part of a large pdu, so that
+ // we don't always started at the begining of a pdu. The Bytes Rcvd
+ // value is set to zero in CompletionRcv when a new pdu is expected
+ //
+ if (pConnectEle->BytesRcvd == 0)
+ {
+
+ if (pSessionHdr->Type == NBT_SESSION_MESSAGE)
+ {
+
+ //
+ // expecting the start of a new session Pkt, so get the length out
+ // of the pTsdu passed in
+ //
+ pConnectEle->TotalPcktLen = myntohl(pSessionHdr->UlongLength);
+
+ // remove the Session header by adjusting the data pointer
+ pTsdu = (PVOID)((PUCHAR)pTsdu + sizeof(tSESSIONHDR));
+
+ // shorten the number of bytes since we have stripped off the
+ // session header
+ BytesIndicated -= sizeof(tSESSIONHDR);
+ BytesAvailable -= sizeof(tSESSIONHDR);
+ *BytesTaken = sizeof(tSESSIONHDR);
+ }
+ //
+ // Session Keep Alive
+ //
+ else
+ if (pSessionHdr->Type == NBT_SESSION_KEEP_ALIVE)
+ {
+ // session keep alives are simply discarded, since the act of sending
+ // a keep alive indicates the session is still alive, otherwise the
+ // transport would report an error.
+
+ // tell the transport that we took the Pdu
+ *BytesTaken = sizeof(tSESSIONHDR);
+ return(STATUS_SUCCESS);
+
+ }
+ else
+ {
+ IF_DBG(NBT_DEBUG_DISCONNECT)
+ KdPrint(("Nbt:Unexpected Session Pdu received: type = %X\n",
+ pSessionHdr->Type));
+
+ ASSERT(0);
+ *BytesTaken = BytesIndicated;
+ return(STATUS_SUCCESS);
+
+ }
+ }
+
+ //
+ // check if there are any receive buffers queued against this connection
+ //
+ if (!IsListEmpty(&pConnectEle->RcvHead))
+ {
+ // get the first buffer off the receive list
+ pRcv = RemoveHeadList(&pConnectEle->RcvHead);
+#ifndef VXD
+ pRcvElement = CONTAINING_RECORD(pRcv,IRP,Tail.Overlay.ListEntry);
+
+ // the cancel routine was set when this irp was posted to Nbt, so
+ // clear it now, since the irp is being passed to the transport
+ //
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine((PIRP)pRcvElement,NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+
+#else
+ pRcvElement = CONTAINING_RECORD(pRcv, RCV_CONTEXT, ListEntry ) ;
+#endif
+
+ //
+ // this buffer is actually an Irp, so pass it back to the transport
+ // as a return parameter
+ //
+ *RcvBuffer = pRcvElement;
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+ }
+
+ //
+ // No receives on this connection. Is there a receive event handler for this
+ // address?
+ //
+ pClientEle = pConnectEle->pClientEle;
+
+#ifdef VXD
+ //
+ // there is always a receive event handler in the Nt case - it may
+ // be the default handler, but it is there, so no need for test.
+ //
+ if (pClientEle->evReceive)
+#endif
+ {
+
+
+ // check that we have not received more data than we should for
+ // this session Pdu. i.e. part of the next session pdu. BytesRcvd may
+ // have a value other than zero if the pdu has arrived in two chunks
+ // and the client has taken the previous one in the indication rather
+ // than passing back an Irp.
+ //
+#if DBG
+ DebugMore = FALSE;
+#endif
+ RemainingPdu = pConnectEle->TotalPcktLen - pConnectEle->BytesRcvd;
+ if (BytesAvailable >= RemainingPdu)
+ {
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:More Data Recvd than expecting! Avail= %X,TotalLen= %X,state=%x\n",
+ BytesAvailable,pConnectEle->TotalPcktLen,pLowerConn->StateRcv));
+#if DBG
+ DebugMore =TRUE;
+#endif
+ // shorten the indication to the client so that they don't
+ // get more data than the end of the pdu
+ //
+ BytesAvailable = RemainingPdu;
+ if (BytesIndicated > BytesAvailable)
+ {
+ BytesIndicated = BytesAvailable;
+ }
+ //
+ // We always indicated at raised IRQL since we call freelockatdispatch
+ // below
+ //
+ ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE | TDI_RECEIVE_AT_DISPATCH_LEVEL;
+ }
+ else
+ {
+ // the transport may have has this flag on. We need to
+ // turn it off if the entire message is not present, where entire
+ // message means within the bytesAvailable length. We deliberately
+ // use bytesavailable so that Rdr/Srv can know that the next
+ // indication will be a new message if they set bytestaken to
+ // bytesavailable.
+ //
+ ReceiveFlags &= ~TDI_RECEIVE_ENTIRE_MESSAGE;
+ ReceiveFlags |= TDI_RECEIVE_AT_DISPATCH_LEVEL;
+#ifndef VXD
+ BytesAvailable = RemainingPdu;
+#endif
+ }
+
+ //
+ // NT-specific code locks pLowerConn before calling this routine,
+ //
+ CTESpinFreeAtDpc(pLowerConn);
+
+ // call the Client Event Handler
+ ClientBytesTaken = 0;
+ status = (*pClientEle->evReceive)(
+ pClientEle->RcvEvContext,
+ pConnectEle->ConnectContext,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ &ClientBytesTaken,
+ pTsdu,
+ &pIrp);
+
+ CTESpinLockAtDpc(pLowerConn);
+#if DBG
+ if (DebugMore)
+ {
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(( "Client TOOK %X bytes, pIrp = %X,status =%X\n",
+ ClientBytesTaken,pIrp,status));
+ }
+#endif
+ if (!pLowerConn->pUpperConnection)
+ {
+ // the connection was disconnected in the interim
+ // so do nothing.
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ CTEIoComplete(pIrp,STATUS_CANCELLED,0);
+ *BytesTaken = BytesAvailable;
+ return(STATUS_SUCCESS);
+ }
+ }
+ else
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ ASSERT(pIrp);
+ //
+ // the client may pass back a receive in the pIrp.
+ // In this case pIrp is a valid receive request Irp
+ // and the status is MORE_PROCESSING
+ //
+
+ // don't put these lines outside the if incase the client
+ // does not set ClientBytesTaken when it returns an error
+ // code... we don't want to use the value then
+ //
+ // count the bytes received so far. Most of the bytes
+ // will be received in the CompletionRcv handler in TdiHndlr.c
+ pConnectEle->BytesRcvd += ClientBytesTaken;
+
+ // The client has taken some of the data at least...
+ *BytesTaken += ClientBytesTaken;
+
+ *RcvBuffer = pIrp;
+
+ // ** FAST PATH **
+ return(status);
+ }
+ else
+ //
+ // no irp was returned... the client just took some of the bytes..
+ //
+ if (status == STATUS_SUCCESS)
+ {
+
+ // count the bytes received so far.
+ pConnectEle->BytesRcvd += ClientBytesTaken;
+ *BytesTaken += ClientBytesTaken;
+
+ //
+ // look at how much data was taken and adjust some counts
+ //
+ if (pConnectEle->BytesRcvd == pConnectEle->TotalPcktLen)
+ {
+ // ** FAST PATH **
+ CHECK_PTR(pConnectEle);
+ pConnectEle->BytesRcvd = 0; // reset for the next session pdu
+ return(status);
+ }
+ else
+ if (pConnectEle->BytesRcvd > pConnectEle->TotalPcktLen)
+ {
+ //IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Too Many Bytes Rcvd!! Rcvd# = %d, TotalLen = %d\n",
+ pConnectEle->BytesRcvd,pConnectEle->TotalPcktLen));
+
+ ASSERTMSG("Nbt:Client Took Too Much Data!!!\n",0);
+
+ //
+ // try to recover by saying that the client took all of the
+ // data so at least the transport is not confused too
+ //
+ *BytesTaken = BytesIndicated;
+
+ }
+ else
+ // the client did not take all of the data so
+ // keep track of the fact
+ {
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("NBT:Client took Indication BytesRcvd=%X, TotalLen=%X BytesAvail %X ClientTaken %X\n",
+ pConnectEle->BytesRcvd,
+ pConnectEle->TotalPcktLen,
+ BytesAvailable,
+ ClientBytesTaken));
+
+ //
+ // the next time the client sends down a receive buffer
+ // the code will pass it to the transport and decrement the
+ // ReceiveIndicated counter which is set in Tdihndlr.c
+
+ }
+ }
+ else
+ if (status == STATUS_DATA_NOT_ACCEPTED)
+ {
+ // client has not taken ANY data...
+ //
+ // In this case the *BytesTaken is set to 4, the session hdr.
+ // since we really have taken that data to setup the PduSize
+ // in the pConnEle structure.
+ //
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("NBT: Status DATA NOT ACCEPTED returned from client Avail %X %X\n",
+ BytesAvailable,pConnectEle));
+
+ // the code in tdihndlr.c normally looks after incrementing
+ // the ReceiveIndicated count for data that is not taken by
+ // the client, but if it is a zero length send that code cannot
+ // detect it, so we put code here to handle that case
+ //
+ // It is possible for the client to do a disconnect after
+ // we release the spin lock on pLowerConn to call the Client's
+ // disconnect indication. If that occurs, do not overwrite
+ // the StateProc with PartialRcv
+ //
+ if ((pConnectEle->TotalPcktLen == 0) &&
+ (pConnectEle->state == NBT_SESSION_UP))
+ {
+ pLowerConn->StateRcv = PARTIAL_RCV;
+ SetStateProc( pLowerConn, PartialRcv ) ;
+ CHECK_PTR(pConnectEle);
+ pConnectEle->ReceiveIndicated = 0; // zero bytes waiting for client
+ }
+ else
+ {
+ //
+ // if any bytes were taken (i.e. the session hdr) then
+ // return status success. (otherwise the status is
+ // statusNotAccpeted).
+ //
+ if (*BytesTaken)
+ {
+ status = STATUS_SUCCESS;
+ }
+ }
+
+ //
+ // the next time the client sends down a receive buffer
+ // the code will pass it to the transport and decrement this
+ // counter.
+ }
+ else
+ ASSERT(0);
+
+
+ return(status);
+
+ }
+#ifdef VXD
+ //
+ // there is always a receive event handler in the Nt case - it may
+ // be the default handler, but it is there, so no need for test.
+ //
+ else
+ {
+ //
+ // there is no client buffer to pass the data to, so keep
+ // track of the fact so when the next client buffer comes down
+ // we can get the data from the transport.
+ //
+ KdPrint(("NBT:Client did not have a Buffer posted, rcvs indicated =%X,BytesRcvd=%X, TotalLen=%X\n",
+ pConnectEle->ReceiveIndicated,
+ pConnectEle->BytesRcvd,
+ pConnectEle->TotalPcktLen));
+
+ // the routine calling this one increments ReceiveIndicated and sets the
+ // state to PartialRcv to keep track of the fact that there is data
+ // waiting in the transport
+ //
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+#endif
+}
+
+//----------------------------------------------------------------------------
+__inline
+ VOID
+DerefLowerConnFast(
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tCONNECTELE *pConnEle,
+ IN CTELockHandle OldIrq
+ )
+/*++
+
+Routine Description:
+
+ This routine dereferences the lower connection and if someone has
+ tried to do that during the execution of the routine that called
+ this one, the pConnEle is dereferenced too.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ // NOTE: we do not coordinate with the pConnEle using InRcvHandler any
+ // more- we just check if pUpperconnection is null or not.
+ //
+ //if (pLowerConn->InRcvHandler)
+ {
+ // pLowerConn->InRcvHandler = FALSE;
+ if (pLowerConn->RefCount > 1)
+ {
+ // This is the FAST PATH
+ pLowerConn->RefCount--;
+ CTESpinFree(pLowerConn,OldIrq);
+ }
+ else
+ {
+ CTESpinFree(pLowerConn,OldIrq);
+ NbtDereferenceLowerConnection(pLowerConn);
+
+ }
+ }
+}
+//----------------------------------------------------------------------------
+ VOID
+DpcGetRestOfIndication(
+ IN PKDPC pDpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when the client has been indicated with more
+ data than they will take and there is a rcv buffer on their RcvHead
+ list when completion rcv runs.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ tCONNECTELE *pConnEle;
+ PIRP pIrp;
+ PIO_STACK_LOCATION pIrpSp;
+ tLOWERCONNECTION *pLowerConn=(tLOWERCONNECTION *)Context;
+ PLIST_ENTRY pEntry;
+
+ CTEMemFree((PVOID)pDpc);
+
+ CTESpinLockAtDpc(&NbtConfig.JointLock);
+
+ // a disconnect indication can come in any time and separate the lower and
+ // upper connections, so check for that
+ if (!pLowerConn->pUpperConnection || pLowerConn->StateRcv != PARTIAL_RCV)
+ {
+ PUSH_LOCATION(0xA4);
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+ //
+ // Dereference pLowerConn
+ //
+ NbtDereferenceLowerConnection(pLowerConn);
+ return;
+ }
+
+ //
+ // get an Irp from the list
+ //
+ status = GetIrp(&pIrp);
+
+ if (!NT_SUCCESS(status))
+ {
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+ KdPrint(("Nbt:Unable to get an Irp - Closing Connection!!\n",0));
+ status = OutOfRsrcKill(pLowerConn);
+ //
+ // Dereference pLowerConn
+ //
+ NbtDereferenceLowerConnection(pLowerConn);
+ return;
+ }
+ CTESpinLockAtDpc(pLowerConn);
+
+ pConnEle = (tCONNECTELE *)pLowerConn->pUpperConnection;
+
+ if (!IsListEmpty(&pConnEle->RcvHead))
+ {
+ PUSH_LOCATION(0xA5);
+ pEntry = RemoveHeadList(&pConnEle->RcvHead);
+
+ CTESpinFreeAtDpc(pLowerConn);
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+
+ pIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
+
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine(pIrp,NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+
+ //
+ // call the same routine that the client would call to post
+ // a recv buffer, except now we are in the PARTIAL_RCV state
+ // and the buffer will be passed to the transport.
+ //
+ status = NTReceive(pLowerConn->pDeviceContext,pIrp);
+
+
+ }
+ else
+ {
+ CTESpinFreeAtDpc(pLowerConn);
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+ PUSH_LOCATION(0xA6);
+ }
+ //
+ // Dereference pLowerConn
+ //
+ NbtDereferenceLowerConnection(pLowerConn);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+DpcHandleNewSessionPdu (
+ IN PKDPC pDpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+/*++
+
+Routine Description:
+
+ This routine simply calls HandleNewSessionPdu from a Dpc started in
+ NewSessionCompletionRoutine.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTEMemFree((PVOID)pDpc);
+
+
+ HandleNewSessionPdu((tLOWERCONNECTION *)Context,(ULONG)SystemArgument1,
+ (ULONG)SystemArgument2);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+HandleNewSessionPdu (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG Offset,
+ IN ULONG ToGet
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the case when a session pdu starts in the middle of
+ a data indication from the transport. It gets an Irp from the free list
+ and formulates a receive to pass to the transport to get that data. The
+ assumption is that the client has taken all data preceding the next session
+ pdu. If the client hasn't then this routine should not be called yet.
+
+Arguments:
+
+
+Return Value:
+
+ pConnectionContext - connection context returned to the transport(connection to use)
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG BytesTaken;
+ PIRP pIrp;
+ PFILE_OBJECT pFileObject;
+ PMDL pMdl;
+ ULONG BytesToGet;
+ tCONNECTELE *pConnEle;
+
+ pIrp = NULL;
+ BytesTaken = 0;
+
+ // we grab the joint lock because it is needed to separate the lower and
+ // upper connections, so with it we can check if they have been separated.
+ //
+ CTESpinLockAtDpc(&NbtConfig.JointLock);
+ pConnEle = pLowerConn->pUpperConnection;
+
+ // a disconnect indication can come in any time and separate the lower and
+ // upper connections, so check for that
+ if (!pLowerConn->pUpperConnection)
+ {
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+ //
+ // remove the reference from CompletionRcv
+ //
+ NbtDereferenceLowerConnection(pLowerConn);
+ return;
+ }
+
+ //
+ // get an Irp from the list
+ //
+ status = GetIrp(&pIrp);
+
+ if (!NT_SUCCESS(status))
+ {
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+ KdPrint(("Nbt:Unable to get an Irp - Closing Connection!!\n",0));
+ status = OutOfRsrcKill(pLowerConn);
+ //
+ // remove the reference from CompletionRcv
+ //
+ NbtDereferenceLowerConnection(pLowerConn);
+ return;
+ }
+ CTESpinLockAtDpc(pLowerConn);
+ //
+ // be sure the connection has not disconnected in the meantime...
+ //
+ if (pLowerConn->State != NBT_SESSION_UP)
+ {
+ REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+ CTESpinFreeAtDpc(pLowerConn);
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+ //
+ // remove the reference from CompletionRcv
+ //
+ NbtDereferenceLowerConnection(pLowerConn);
+ return;
+ }
+
+ pFileObject = pLowerConn->pFileObject;
+
+ // use the indication buffer for the receive.
+ pMdl = pLowerConn->pIndicateMdl;
+
+ // this flag is set below so we know if there is data in the indicate buffer
+ // or not.
+ if (Offset)
+ {
+ PVOID NewAddress;
+ PMDL pNewMdl;
+
+ // there is still data in the indication buffer ,so only
+ // fill the empty space. This means adjusting the Mdl to
+ // to only map the last portion of the Indication Buffer
+ NewAddress = (PVOID)((PCHAR)MmGetMdlVirtualAddress(pMdl)
+ + Offset);
+
+ // create a partial MDL so that the new data is copied after the existing data
+ // in the MDL.
+ //
+ // 0 for length means map the rest of the buffer
+ //
+ pNewMdl = pConnEle->pNewMdl;
+
+ IoBuildPartialMdl(pMdl,pNewMdl,NewAddress,0);
+
+ pMdl = pNewMdl;
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Mapping IndicBuffer to partial Mdl Offset=%X, ToGet=%X %X\n",
+ Offset,ToGet,
+ pLowerConn));
+ }
+ else
+ {
+ CHECK_PTR(pLowerConn);
+ pLowerConn->BytesInIndicate = 0;
+ }
+
+ //
+ // Only get the amount of data specified, which is either the 4 byte header
+ // or the rest of the pdu so that we never have
+ // more than one session pdu in the indicate buffer.
+ //
+ BytesToGet = ToGet;
+
+ TdiBuildReceive(
+ pIrp,
+ IoGetRelatedDeviceObject(pFileObject),
+ pFileObject,
+ NewSessionCompletionRoutine,
+ (PVOID)pLowerConn,
+ pMdl,
+ (ULONG)TDI_RECEIVE_NORMAL,
+ BytesToGet); // only ask for the number of bytes left and no more
+
+ CTESpinFreeAtDpc(pLowerConn);
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+
+ CHECK_COMPLETION(pIrp);
+ status = IoCallDriver(IoGetRelatedDeviceObject(pFileObject),pIrp);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NewSessionCompletionRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion of the receive to get the remaining
+ data left in the transport when a session PDU starts in the middle of
+ an indication from the transport. This routine is run as the completion
+ of a recv Irp passed to the transport by NBT, to get the remainder of the
+ data in the transport.
+
+ The routine then calls the normal receive handler, which can either
+ consume the data or pass back an Irp. If an Irp is passed back then
+ the data is copied into that irp in this routine.
+
+Arguments:
+
+
+Return Value:
+
+ pConnectionContext - connection context returned to the transport(connection to use)
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ ULONG BytesTaken;
+ tCONNECTELE *pConnEle;
+ PVOID pData;
+ KIRQL OldIrq;
+ PMDL pMdl;
+ ULONG BytesIndicated;
+ ULONG BytesAvailable;
+ PKDPC pDpc;
+ tLOWERCONNECTION *pLowerConn;
+ ULONG Length;
+ ULONG PduLen;
+ PIRP pRetIrp;
+
+ // we grab the joint lock because it is needed to separate the lower and
+ // upper connections, so with it we can check if they have been separated.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pLowerConn = (tLOWERCONNECTION *)pContext;
+ pConnEle = pLowerConn->pUpperConnection;
+
+ CTESpinLockAtDpc(pLowerConn);
+
+ // a disconnect indication can come in any time and separate the lower and
+ // upper connections, so check for that
+ //
+ if (!pConnEle)
+ {
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+ status = STATUS_UNSUCCESSFUL;
+ goto ExitRoutine;
+ }
+
+ CTESpinFreeAtDpc(&NbtConfig.JointLock);
+
+
+ BytesTaken = 0;
+
+ pMdl = pLowerConn->pIndicateMdl;
+
+ pData = MmGetMdlVirtualAddress(pMdl);
+
+ //
+ // The Indication buffer may have more data in it than what we think
+ // was left in the transport, because the transport may have received more
+ // data in the intervening time. Check for this case.
+ //
+ if (pIrp->IoStatus.Information > pConnEle->BytesInXport)
+ {
+ // no data left in transport
+ //
+ CHECK_PTR(pConnEle);
+ pConnEle->BytesInXport = 0;
+ }
+ else
+ {
+ //
+ // subtract what we just retrieved from the transport, from the count
+ // of data left in the transport
+ //
+ pConnEle->BytesInXport -= pIrp->IoStatus.Information;
+ }
+ // put the irp back on its free list
+ CHECK_PTR(pIrp);
+ pIrp->MdlAddress = NULL;
+
+ REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+
+
+ //
+ // there may be data still in the indication buffer,
+ // so add that amount to what we just received.
+ //
+ pLowerConn->BytesInIndicate += (USHORT)pIrp->IoStatus.Information;
+ BytesIndicated = pLowerConn->BytesInIndicate;
+ //
+ // we need to set the bytes available to be the data in the Xport + the
+ // bytes in the indicate buffer, so that
+ // ReceiveIndicated gets set to the correct value if the client does
+ // not take all of data
+ //
+ BytesAvailable = pConnEle->BytesInXport + BytesIndicated;
+ pRetIrp = NULL;
+
+ // if the number of bytes is 4 then we just have the header and must go
+ // back to the transport for the rest of the pdu, or we have a keep
+ // alive pdu...
+ //
+ //
+ // This could be a session keep alive pdu so check the pdu type. Keep
+ // alives just go to the RcvHndlrNotOs routine and return, doing nothing.
+ // They have a length of zero, so the overall length is 4 and they could
+ // be confused for session pdus otherwise.
+ //
+ status = STATUS_SUCCESS;
+ if (BytesIndicated == sizeof(tSESSIONHDR))
+ {
+
+ PUSH_LOCATION(0x1e)
+ if (((tSESSIONHDR UNALIGNED *)pData)->Type == NBT_SESSION_MESSAGE)
+ {
+ // if there is still data in the transport we must send down an
+ // irp to get the data, however, if there is no data left in
+ // the transport, then the data will come up on its own, into
+ // the indicate_buffer case in the main Receivehandler.
+ //
+ if (pConnEle->BytesInXport)
+ {
+ PUSH_LOCATION(0x1e);
+
+ // tell the DPC routine to get the data at an offset of 4 for length Length
+
+ //
+ // this is the first indication to find out how large the pdu is, so
+ // get the length and go get the rest of the pdu.
+ //
+ Length = myntohl(((tSESSIONHDR UNALIGNED *)pData)->UlongLength);
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Got Pdu Hdr in sessioncmplionroutine, PduLen =%X\n",Length));
+
+ // it is possible to get a zero length pdu, in which case we
+ // do NOT need to go to the transport to get more data
+ //
+ if (Length)
+ {
+ PUSH_LOCATION(0x1e);
+ //
+ // now go get this amount of data and add it to the header
+ //
+ pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('r'));
+
+ ASSERT(pDpc);
+
+ KeInitializeDpc(pDpc,
+ DpcHandleNewSessionPdu,
+ (PVOID)pLowerConn);
+
+
+ CTESpinFree(pLowerConn,OldIrq);
+
+ // check that the pdu is not going to overflow the indicate buffer.
+ //
+ if (Length > NBT_INDICATE_BUFFER_SIZE - sizeof(tSESSIONHDR))
+ {
+ Length = NBT_INDICATE_BUFFER_SIZE - sizeof(tSESSIONHDR);
+ }
+
+ ASSERTMSG("Nbt:Getting ZERO bytes from Xport!!\n",Length);
+
+ KeInsertQueueDpc(pDpc,(PVOID)sizeof(tSESSIONHDR),(PVOID)Length);
+
+ // clean up the partial mdl since we are going to turn around and reuse
+ // it in HandleNewSessionPdu above..
+ //
+ // THIS CALL SHOULD NOT BE NEEDED SINCE THE INDICATE BUFFER IS NON_PAGED
+ // POOL
+// MmPrepareMdlForReuse(pConnEle->pNewMdl);
+
+ // return this status to stop to tell the io subsystem to stop processing
+ // this irp when we return it.
+ //
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+ }
+ }
+
+
+ }
+ }
+
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:NewSessComplRcv BytesinXport= %X,InIndicate=%X Indic. %X,Avail=%X %X\n",
+ pConnEle->BytesInXport,pLowerConn->BytesInIndicate,BytesIndicated,
+ BytesAvailable,pConnEle->pLowerConnId));
+
+
+ if (!NT_SUCCESS(pIrp->IoStatus.Status))
+ {
+ ASSERTMSG("Nbt:Not Expecting a Bad Status Code\n",0);
+ goto ExitRoutine;
+ }
+
+ //
+ // check if we have a whole pdu in the indicate buffer or not. IF not
+ // then just return and wait for more data to hit the TdiReceiveHandler
+ // code. This check passes KeepAlives correctly since they have a pdu
+ // length of 0, and adding the header gives 4, their overall length.
+ //
+ PduLen = myntohl(((tSESSIONHDR UNALIGNED *)pData)->UlongLength);
+ if ((BytesIndicated < PduLen + sizeof(tSESSIONHDR)) &&
+ (BytesIndicated != NBT_INDICATE_BUFFER_SIZE))
+
+ {
+ PUSH_LOCATION(0x1f);
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Returning in NewSessionCompletion BytesIndicated = %X\n",
+ BytesIndicated));
+ }
+ else
+ {
+ PUSH_LOCATION(0x20);
+
+ status = CopyDataandIndicate(
+ NULL,
+ (PVOID)pLowerConn,
+ 0, // rcv flags
+ BytesIndicated,
+ BytesAvailable,
+ &BytesTaken,
+ pData,
+ (PVOID)&pRetIrp);
+
+// status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ }
+
+ExitRoutine:
+ //
+ // check if an irp is passed back, so we don't Deref in that case.
+ //
+ if (status != STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ //
+ // quickly check if we can just decrement the ref count without calling
+ // nbtDereferenceConnection
+ //
+ PUSH_LOCATION(0x51);
+ DerefLowerConnFast(pLowerConn,pConnEle,OldIrq);
+ }
+ else
+ {
+ CTESpinFree(pLowerConn,OldIrq);
+ }
+
+
+
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NtBuildIndicateForReceive (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG Length,
+ OUT PVOID *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine sets up the indicate buffer to get data from the transport
+ when the indicate buffer already has some data in it. A partial MDL is
+ built and the attached to the irp.
+ before we indicate.
+
+Arguments:
+
+
+Return Value:
+
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ PIRP pIrp;
+ PTDI_REQUEST_KERNEL_RECEIVE pParams;
+ PIO_STACK_LOCATION pIrpSp;
+ tCONNECTELE *pConnEle;
+ PMDL pNewMdl;
+ PVOID NewAddress;
+
+ //
+ // get an Irp from the list
+ //
+
+ status = GetIrp(&pIrp);
+
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("NBT:Unable to get Irp, Kill connection\n"));
+
+ CTESpinFreeAtDpc(pLowerConn);
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLockAtDpc(pLowerConn);
+
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pConnEle= pLowerConn->pUpperConnection;
+
+ NewAddress = (PVOID)((PCHAR)MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl)
+ + pLowerConn->BytesInIndicate);
+
+ // create a partial MDL so that the new data is copied after the existing data
+ // in the MDL.
+ //
+ // 0 for length means map the rest of the buffer
+ //
+ pNewMdl = pConnEle->pNewMdl;
+
+ IoBuildPartialMdl(pLowerConn->pIndicateMdl,pNewMdl,NewAddress,0);
+
+ TdiBuildReceive(
+ pIrp,
+ IoGetRelatedDeviceObject(pLowerConn->pFileObject),
+ pLowerConn->pFileObject,
+ NewSessionCompletionRoutine,
+ (PVOID)pLowerConn,
+ pNewMdl,
+ (ULONG)TDI_RECEIVE_NORMAL,
+ Length);
+
+ //
+ // we need to set the next Irp stack location because this irp is returned
+ // as a return parameter rather than being passed through IoCallDriver
+ // which increments the stack location itself
+ //
+ ASSERT(pIrp->CurrentLocation > 1);
+ IoSetNextIrpStackLocation(pIrp);
+
+ *ppIrp = (PVOID)pIrp;
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NtBuildIrpForReceive (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG Length,
+ OUT PVOID *ppIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine gets an Irp to be used to receive data and hooks the indication
+ Mdl to it, so we can accumulate at least 128 bytes of data for the client
+ before we indicate.
+
+Arguments:
+
+
+Return Value:
+
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ PIRP pIrp;
+ PTDI_REQUEST_KERNEL_RECEIVE pParams;
+ PIO_STACK_LOCATION pIrpSp;
+
+ //
+ // get an Irp from the list
+ //
+ status = GetIrp(&pIrp);
+
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("NBT:Unable to get Irp, Kill connection\n"));
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ CHECK_PTR(pLowerConn);
+ pLowerConn->BytesInIndicate = 0;
+
+ TdiBuildReceive(
+ pIrp,
+ IoGetRelatedDeviceObject(pLowerConn->pFileObject),
+ pLowerConn->pFileObject,
+ NewSessionCompletionRoutine,
+ (PVOID)pLowerConn,
+ pLowerConn->pIndicateMdl,
+ (ULONG)TDI_RECEIVE_NORMAL,
+ Length);
+
+ //
+ // we need to set the next Irp stack location because this irp is returned
+ // as a return parameter rather than being passed through IoCallDriver
+ // which increments the stack location itself
+ //
+ ASSERT(pIrp->CurrentLocation > 1);
+ IoSetNextIrpStackLocation(pIrp);
+
+ *ppIrp = (PVOID)pIrp;
+
+ return(STATUS_SUCCESS);
+}
+
+#pragma inline_depth(0)
+//----------------------------------------------------------------------------
+ NTSTATUS
+CopyDataandIndicate(
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT PIRP *ppIrp
+ )
+/*++
+
+Routine Description:
+
+
+ This routine combines data indicated with the indicate buffer to
+ indicate the total to the client. Any bytes Indicated are those bytes
+ in the indicate buffer. Bytes available adds in any bytes in the transport.
+
+ The idea here is to copy as much as possible from the indicate buffer and
+ then pass back an irp if there is still more data in the transport. If
+ no data left in the transport, this routine completes the client irp and
+ returns STATUS_SUCCESS.
+
+Arguments:
+
+
+Return Value:
+
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnEle;
+ ULONG BytesCopied;
+ ULONG Indicated;
+ ULONG Available;
+ ULONG Taken;
+ ULONG AmountAlreadyInIndicateBuffer;
+ PVOID pBuffer;
+ PIRP pIrp;
+ BOOLEAN bReIndicate=FALSE;
+ ULONG RemainingPdu;
+ ULONG ToCopy;
+ PKDPC pDpc;
+ ULONG SaveInXport;
+ ULONG PduSize;
+
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+ pConnEle = pLowerConn->pUpperConnection;
+
+ AmountAlreadyInIndicateBuffer = pLowerConn->BytesInIndicate;
+
+ //
+ // set the parameters for the call to the TdiReceiveHandler routine
+ //
+
+ Indicated = BytesIndicated;
+ Available = BytesAvailable;
+ Taken = 0;
+
+
+ ASSERT(pLowerConn->StateRcv == INDICATE_BUFFER);
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Amount In Indicate = %X\n",AmountAlreadyInIndicateBuffer));
+
+ // now that we have 128 bytes (plus the session hdr = 132 total) we
+ // can indicate to the client
+
+ pBuffer = MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl);
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:FromCopyData, BytesAvail= %X,BytesInd= %X,BytesRcvd= %X,Amount=%X, %X,state=%X,RcvEC=%X\n",
+ Available,Indicated,pConnEle->BytesRcvd,
+ AmountAlreadyInIndicateBuffer,pLowerConn,pLowerConn->StateRcv,
+ ReceiveEventContext));
+
+ pIrp = NULL;
+
+ //
+ // Reset this count so that the routine processes the Session header correctly
+ //
+ CHECK_PTR(pConnEle);
+ pConnEle->BytesRcvd = 0;
+ PUSH_LOCATION(0x21);
+ status = RcvHandlrNotOs(
+ NULL,
+ ConnectionContext,
+ ReceiveFlags,
+ Indicated,
+ Available,
+ &Taken,
+ pBuffer,
+ (PVOID)&pIrp
+ );
+
+ //
+ // if the connection has disonnected, then just return
+ //
+ if (!pLowerConn->pUpperConnection)
+ {
+ *BytesTaken = BytesAvailable;
+ return(STATUS_SUCCESS);
+ }
+
+ // do not use pConnEle->TotalPcktLen here becauase it won't be set for
+ // keep alives - must use actual buffer to get length.
+ PduSize = myntohl(((tSESSIONHDR UNALIGNED *)pBuffer)->UlongLength) + sizeof(tSESSIONHDR);
+
+ RemainingPdu = pConnEle->TotalPcktLen - pConnEle->BytesRcvd;
+
+ if (Taken <= pLowerConn->BytesInIndicate)
+ {
+ pLowerConn->BytesInIndicate -= (USHORT)Taken;
+ }
+ else
+ {
+ pLowerConn->BytesInIndicate = 0;
+ }
+
+ if (pIrp)
+ {
+ PIO_STACK_LOCATION pIrpSp;
+ PTDI_REQUEST_KERNEL_RECEIVE pParams;
+ ULONG ClientRcvLen;
+
+ PUSH_LOCATION(0x22);
+ //
+ // BytesInXport will be recalculated by ProcessIrp based on BytesAvailable
+ // and the ClientRcvLength, so set it to 0 here.
+ //
+ SaveInXport = pConnEle->BytesInXport;
+ CHECK_PTR(pConnEle);
+ pConnEle->BytesInXport = 0;
+ status = ProcessIrp(pLowerConn,
+ pIrp,
+ pBuffer,
+ &Taken,
+ Indicated,
+ Available);
+
+ //
+ // copy the data in the indicate buffer that was not taken by the client
+ // into the MDL and then update the bytes taken and pass the irp on downwar
+ // to the transport
+ //
+ ToCopy = Indicated - Taken;
+
+ // the Next stack location has the correct info in it because we
+ // called TdiRecieveHandler with a null ReceiveEventContext,
+ // so that routine does not increment the stack location
+ //
+ pIrpSp = IoGetNextIrpStackLocation(pIrp);
+ pParams = (PTDI_REQUEST_KERNEL_RECEIVE)&pIrpSp->Parameters;
+ ClientRcvLen = pParams->ReceiveLength;
+
+ // did the client's Pdu fit entirely into the indication buffer?
+ //
+ if (ClientRcvLen <= ToCopy)
+ {
+ PUSH_LOCATION(0x23);
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Took some(or all) RemainingPdu= %X, ClientRcvLen= %X,InXport=%X %X\n",
+ RemainingPdu,ClientRcvLen,pConnEle->BytesInXport,pLowerConn));
+
+ // if ProcessIrp has recalculated the bytes in the Xport
+ // then set it back to where it should be, Since ProcessIrp will
+ // put all not taken bytes as bytes in the transport - but some
+ // of the bytes are still in the indicate buffer.
+ //
+ pConnEle->BytesInXport = SaveInXport;
+
+ // it could be a zero length send where the client returns a null
+ // mdl, or the client returns an mdl and the RcvLen is really zero.
+ //
+ if (pIrp->MdlAddress && ClientRcvLen)
+ {
+ TdiCopyBufferToMdl(pBuffer, // indicate buffer
+ Taken, // src offset
+ ClientRcvLen,
+ pIrp->MdlAddress,
+ 0, // dest offset
+ &BytesCopied);
+ }
+ else
+ BytesCopied = 0;
+
+ //
+ // check for data still in the transport - subtract data copied to
+ // Irp, since Taken was already subtracted.
+ //
+ pLowerConn->BytesInIndicate -= (USHORT)BytesCopied;
+
+ *BytesTaken = Taken + BytesCopied;
+ ASSERT(BytesCopied == ClientRcvLen);
+
+ // the client has received all of the data, so complete his irp
+ //
+ pIrp->IoStatus.Information = BytesCopied;
+ pIrp->IoStatus.Status = STATUS_SUCCESS;
+
+ // since we are completing it and TdiRcvHandler did not set the next
+ // one.
+ //
+ ASSERT(pIrp->CurrentLocation > 1);
+
+ // since we are completing the irp here, no need to call
+ // this, because it will complete through completionrcv.
+ IoSetNextIrpStackLocation(pIrp);
+
+ // there should not be any data in the indicate buffer since it
+ // only holds either 132 bytes or a whole pdu unless the client
+ // receive length is too short...
+ //
+ if (pLowerConn->BytesInIndicate)
+ {
+ PUSH_LOCATION(0x23);
+ // when the irp goes through completionRcv it should set the
+ // state to PartialRcv and the next posted buffer from
+ // the client should pickup this data.
+ CopyToStartofIndicate(pLowerConn,(Taken+BytesCopied));
+ }
+ else
+ {
+ //
+ // this will complete through CompletionRcv and for that
+ // reason it will get any more data left in the transport. The
+ // Completion routine will set the correct state for the rcv when
+ // it processes this Irp ( to INDICATED, if needed). ProcessIrp
+ // may have set ReceiveIndicated, so that CompletionRcv will
+ // set the state to PARTIAL_RCV when it runs.
+ //
+ pLowerConn->StateRcv = NORMAL;
+ pLowerConn->CurrentStateProc = Normal;
+ }
+
+ CTESpinFreeAtDpc(pLowerConn);
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ CTESpinLockAtDpc(pLowerConn);
+ //
+ // this was undone by CompletionRcv, so redo them, since the
+ // caller will undo them again.
+ //
+ pLowerConn->RefCount++;
+
+ return(STATUS_SUCCESS);
+ }
+ else
+ {
+
+ PUSH_LOCATION(0x24);
+ //
+ // there is still data that we need to get to fill the PDU. There
+ // may be more data left in the transport or not after the irp is
+ // filled.
+ // In either case the Irps' Mdl must be adjusted to account for
+ // filling part of it.
+ //
+ TdiCopyBufferToMdl(pBuffer, // IndicateBuffer
+ Taken, // src offset
+ ToCopy,
+ pIrp->MdlAddress,
+ 0, // dest offset
+ &BytesCopied);
+
+ //
+ // save the Mdl so we can reconstruct things later
+ //
+ pLowerConn->pMdl = pIrp->MdlAddress;
+ pConnEle->pNextMdl = pIrp->MdlAddress;
+ ASSERT(pIrp->MdlAddress);
+ //
+ // The irp is being passed back to the transport, so we NULL
+ // our ptr to it so we don't try to cancel it on a disconnect
+ //
+ CHECK_PTR(pConnEle);
+ pConnEle->pIrpRcv = NULL;
+
+ // Adjust the number of bytes in the Mdl chain so far since the
+ // completion routine will only count the bytes filled in by the
+ // transport
+ //
+ pConnEle->BytesRcvd += BytesCopied;
+
+ *BytesTaken = BytesIndicated;
+
+ //
+ // clear the number of bytes in the indicate buffer since the client
+ // has taken more than the data left in the Indicate buffer
+ //
+ CHECK_PTR(pLowerConn);
+ pLowerConn->BytesInIndicate = 0;
+
+ // decrement the client rcv len by the amount already put into the
+ // client Mdl
+ //
+ ClientRcvLen -= BytesCopied;
+ //
+ // if ProcessIrp did recalculate the bytes in the transport
+ // then set back to what it was. Process irp will do this
+ // recalculation if the clientrcv buffer is too short only.
+ //
+ pConnEle->BytesInXport = SaveInXport;
+
+ //
+ // adjust the number of bytes downward due to the client rcv
+ // buffer
+ //
+ if (ClientRcvLen < SaveInXport)
+ {
+ PUSH_LOCATION(0x24);
+ pConnEle->BytesInXport -= ClientRcvLen;
+ }
+ else
+ {
+ pConnEle->BytesInXport = 0;
+ }
+
+ // ProcessIrp will set bytesinXport and ReceiveIndicated - since
+ // the indicate buffer is empty that calculation of BytesInXport
+ // will be correct.
+ //
+
+ // We MUST set the state to FILL_IRP so that completion Rcv
+ // undoes the partial MDL stuff - i.e. it puts the original
+ // MdlAddress in the Irp, rather than the partial Mdl address.
+ // CompletionRcv will set the state to partial Rcv if ReceiveIndicated
+ // is not zero.
+ //
+ pLowerConn->StateRcv = FILL_IRP;
+ pLowerConn->CurrentStateProc = FillIrp;
+
+ // the client is going to take more data from the transport with
+ // this Irp. Set the new Rcv Length that accounts for the data just
+ // copied to the Irp.
+ //
+ pParams->ReceiveLength = ClientRcvLen;
+
+ // keep track of data in MDL so we know when it is full and we need to
+ // return it to the user - ProcessIrp set it to ClientRcvLen, so
+ // shorten it here.
+ //
+ pConnEle->FreeBytesInMdl -= BytesCopied;
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:ClientRcvLen = %X, LeftinXport= %X RemainingPdu= %X %X\n",ClientRcvLen,
+ pConnEle->BytesInXport,RemainingPdu,pLowerConn));
+
+
+ // Build a partial Mdl to represent the client's Mdl chain since
+ // we have copied data to it, and the transport must copy
+ // more data to it after that data.
+ //
+ MakePartialMdl(pConnEle,pIrp,BytesCopied);
+
+ *ppIrp = pIrp;
+
+ // increments the stack location, since TdiReceiveHandler did not.
+ //
+ if (ReceiveEventContext)
+ {
+ ASSERT(pIrp->CurrentLocation > 1);
+ IoSetNextIrpStackLocation(pIrp);
+
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+ }
+ else
+ {
+ // pass the Irp to the transport since we were called from
+ // NewSessionCompletionRoutine
+ //
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Calling IoCallDriver\n"));
+ ASSERT(pIrp->CurrentLocation > 1);
+
+ CTESpinFreeAtDpc(pLowerConn);
+ CHECK_COMPLETION(pIrp);
+ IoCallDriver(IoGetRelatedDeviceObject(pLowerConn->pFileObject),pIrp);
+ CTESpinLockAtDpc(pLowerConn);
+
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+ }
+
+
+ }
+ }
+ else
+ {
+ PUSH_LOCATION(0x54);
+ //
+ // no Irp passed back, the client just took some or all of the data
+ //
+ *BytesTaken = Taken;
+ pLowerConn->BytesRcvd += Taken - sizeof(tSESSIONHDR);
+
+ ASSERT(*BytesTaken < 0x7FFFFFFF );
+
+ //
+ // if more than the indicate buffer is taken, then the client
+ // is probably trying to say it doesn't want any more of the
+ // message.
+ //
+ if (Taken > BytesIndicated)
+ {
+ //
+ // in this case the client has taken more than the indicated.
+ // We set bytesavailable to the message length in RcvHndlrNotOs,
+ // so the client has probably said BytesTaken=BytesAvailable.
+ // So kill the connection
+ // because we have no way of handling this case here, since
+ // part of the message may still be in the transport, and we
+ // might have to send the indicate buffer down there multiple
+ // times to get all of it...a mess! The Rdr only sets bytestaken =
+ // bytesAvailable under select error conditions anyway.
+ //
+ CTESpinFreeAtDpc(pLowerConn);
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLockAtDpc(pLowerConn);
+
+ *BytesTaken = BytesAvailable;
+
+ }
+ else
+ if (pLowerConn->StateRcv == PARTIAL_RCV)
+ {
+ // this may be a zero length send -that the client has
+ // decided not to accept. If so then the state will be set
+ // to PartialRcv. In this case do NOT go down to the transport
+ // and get the rest of the data, but wait for the client
+ // to post a rcv buffer.
+ //
+ PUSH_LOCATION(0x54);
+ return(STATUS_SUCCESS);
+ }
+ else
+ if (Taken == PduSize)
+ {
+ //
+ // Must have taken all of the pdu data, so check for
+ // more data available - if so send down the indicate
+ // buffer to get it.
+ //
+ if (pConnEle->BytesInXport)
+ {
+ PUSH_LOCATION(0x28);
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:CopyData BytesInXport= %X, %X\n",pConnEle->BytesInXport,
+ pLowerConn));
+
+ //
+ // there is still data in the transport so Q a Dpc to use
+ // the indicate buffer to get the data
+ //
+ pDpc = NbtAllocMem(sizeof(KDPC),NBT_TAG('s'));
+
+ if (pDpc)
+ {
+ KeInitializeDpc(pDpc,
+ DpcHandleNewSessionPdu,
+ (PVOID)pLowerConn);
+
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+ pLowerConn->CurrentStateProc = IndicateBuffer;
+
+ // get just the header first to see how large the pdu is
+ //
+ pLowerConn->RefCount++;
+ KeInsertQueueDpc(pDpc,NULL,(PVOID)sizeof(tSESSIONHDR));
+ }
+ else
+ {
+ CTESpinFreeAtDpc(pLowerConn);
+ OutOfRsrcKill(pLowerConn);
+ CTESpinLockAtDpc(pLowerConn);
+ }
+
+ }
+ else
+ {
+ PUSH_LOCATION(0x29);
+ //
+ // clear the flag saying that we are using the indicate buffer
+ //
+ pLowerConn->StateRcv = NORMAL;
+ pLowerConn->CurrentStateProc = Normal;
+
+ }
+
+ PUSH_LOCATION(0x2a);
+ return(STATUS_SUCCESS);
+
+ }
+ else
+ {
+ //
+ // the client may have taken all the data in the
+ // indication!!, in which case return status success
+ // Note: that we check bytes available here not bytes
+ // indicated - since the client could take all indicated
+ // data but still leave data in the transport. If the client
+ // got told there was more available but only took the indicated,
+ // the we need to do the else and track ReceiveIndicated, but if
+ // Indicated == Available, then we take the if and wait for
+ // another indication from the transport.
+ //
+ if (Taken == BytesAvailable)
+ {
+ PUSH_LOCATION(0x4);
+ status = STATUS_SUCCESS;
+
+ }
+ else
+ {
+
+ // did not take all of the data in the Indication
+ //
+
+ PUSH_LOCATION(0x2b);
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Took Part of indication... BytesRemaining= %X, LeftInXport= %X, %X\n",
+ pLowerConn->BytesInIndicate,pConnEle->BytesInXport,pLowerConn));
+
+ //
+ // The amount of data Indicated to the client should not exceed
+ // the Pdu size, so check that, since this routine could get
+ // called with bytesAvailable > than the Pdu size.
+ //
+ // That is checked above where we check if Taken > BytesIndicated.
+
+ SaveInXport = pConnEle->BytesInXport;
+ ASSERT(Taken <= PduSize);
+ status = ClientTookSomeOfTheData(pLowerConn,
+ Indicated,
+ Available,
+ Taken,
+ PduSize);
+
+ //
+ // Since the data may be divided between some in the transport
+ // and some in the indicate buffer do not let ClientTookSomeOf...
+ // recalculate the amount in the transport, since it assumes all
+ // untaken data is in the transport. Since the client did not
+ // take of the indication, the Bytes in Xport have not changed.
+ //
+ pConnEle->BytesInXport = SaveInXport;
+ //
+ // need to move the data forward in the indicate buffer so that
+ // it begins at the start of the buffer
+ //
+ if (Taken)
+ {
+ CopyToStartofIndicate(pLowerConn,Taken);
+ }
+
+ }
+ }
+
+ }
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiConnectHandler (
+ IN PVOID pConnectEventContext,
+ IN int RemoteAddressLength,
+ IN PVOID pRemoteAddress,
+ IN int UserDataLength,
+ IN PVOID UNALIGNED pUserData,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ OUT CONNECTION_CONTEXT *pConnectionContext,
+ OUT PIRP *ppAcceptIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine is connect event handler. It is invoked when a request for
+ a connection has been received by the provider. NBT accepts the connection
+ on one of its connections in its LowerConnFree list
+
+ Initially a TCP connection is setup with this port. Then a Session Request
+ packet is sent across the connection to indicate the name of the destination
+ process. This packet is received in the RcvHandler.
+
+Arguments:
+
+ pConnectEventContext - the context passed to the transport when this event was setup
+ RemoteAddressLength - the length of the source address (4 bytes for IP)
+ pRemoteAddress - a ptr to the source address
+ UserDataLength - the number of bytes of user data - includes the session Request hdr
+ pUserData - ptr the the user data passed in
+ OptionsLength - number of options to pass in
+ pOptions - ptr to the options
+
+Return Value:
+
+ pConnectionContext - connection context returned to the transport(connection to use)
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ PFILE_OBJECT pFileObject;
+ PIRP pRequestIrp;
+ CONNECTION_CONTEXT pConnectionId;
+ tDEVICECONTEXT *pDeviceContext;
+
+ *pConnectionContext = NULL;
+
+ // convert the context value into the device context record ptr
+ pDeviceContext = (tDEVICECONTEXT *)pConnectEventContext;
+
+ IF_DBG(NBT_DEBUG_TDIHNDLR)
+ KdPrint(("pDeviceContxt = %X ConnectEv = %X",pDeviceContext,pConnectEventContext));
+ ASSERTMSG("Bad Device context passed to the Connection Event Handler",
+ pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+
+ // get an Irp from the list
+ status = GetIrp(&pRequestIrp);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // call the non-OS specific routine to find a free connection.
+
+ status = ConnectHndlrNotOs(
+ pConnectEventContext,
+ RemoteAddressLength,
+ pRemoteAddress,
+ UserDataLength,
+ pUserData,
+ &pConnectionId);
+
+
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_TDIHNDLR)
+ KdPrint(("NO FREE CONNECTIONS in connect handler\n"));
+
+ // put the Irp back on its free list
+ //
+ REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pRequestIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ pFileObject = ((tLOWERCONNECTION *)pConnectionId)->pFileObject;
+
+ TdiBuildAccept(
+ pRequestIrp,
+ IoGetRelatedDeviceObject(pFileObject),
+ pFileObject,
+ AcceptCompletionRoutine,
+ (PVOID)pConnectionId,
+ NULL,
+ NULL);
+
+ // we need to null the MDL address because the transport KEEPS trying to
+ // release buffers!! which do not exist!!!
+ //
+ CHECK_PTR(pRequestIrp);
+ pRequestIrp->MdlAddress = NULL;
+
+
+ // return the connection id to accept the connect indication on.
+ *pConnectionContext = (CONNECTION_CONTEXT)pConnectionId;
+ *ppAcceptIrp = pRequestIrp;
+ //
+ // make the next stack location the current one. Normally IoCallDriver
+ // would do this but we are not going through IoCallDriver here, since the
+ // Irp is just passed back with Connect Indication.
+ //
+ ASSERT(pRequestIrp->CurrentLocation > 1);
+ IoSetNextIrpStackLocation(pRequestIrp);
+
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+AcceptCompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion of an Accept to the transport.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ tLOWERCONNECTION *pLowerConn;
+ CTELockHandle OldIrq;
+ tDEVICECONTEXT *pDeviceContext;
+
+ pLowerConn = (tLOWERCONNECTION *)pContext;
+ pDeviceContext = pLowerConn->pDeviceContext;
+
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ CTESpinLockAtDpc(pLowerConn);
+ //
+ // if the connection disconnects before the connect accept irp (this irp)
+ // completes do not put back on the free list here but let nbtdisconnect
+ // handle it.
+ // (i.e if the state is no longer INBOUND, then don't touch the connection
+ //
+ if ((!NT_SUCCESS(pIrp->IoStatus.Status)) &&
+ (pLowerConn->State == NBT_SESSION_INBOUND))
+ {
+
+ //
+ // the accept failed, so close the connection and create
+ // a new one to be sure all activity is run down on the connection.
+ //
+
+ pLowerConn->State = NBT_IDLE;
+
+ CTESpinFreeAtDpc(pLowerConn);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ KdPrint(("AcceptCompletionRoutine: error: %lx\n", pIrp->IoStatus.Status));
+
+ CTEQueueForNonDispProcessing(
+ NULL,
+ pLowerConn,
+ NULL,
+ CleanupAfterDisconnect,
+ pDeviceContext);
+
+ PUSH_LOCATION(0x93);
+ }
+ else
+ {
+ CTESpinFreeAtDpc(pLowerConn);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+
+ // put the Irp back on its free list
+ REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+
+ // return this status to stop the IO subsystem from further processing the
+ // IRP - i.e. trying to complete it back to the initiating thread! -since
+ // there is not initiating thread - we are the initiator
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiDisconnectHandler (
+ IN PVOID EventContext,
+ IN PVOID ConnectionContext,
+ IN ULONG DisconnectDataLength,
+ IN PVOID pDisconnectData,
+ IN ULONG DisconnectInformationLength,
+ IN PVOID pDisconnectInformation,
+ IN ULONG DisconnectIndicators
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a session is disconnected from a remote
+ machine.
+
+Arguments:
+
+ IN PVOID EventContext,
+ IN PCONNECTION_CONTEXT ConnectionContext,
+ IN ULONG DisconnectDataLength,
+ IN PVOID DisconnectData,
+ IN ULONG DisconnectInformationLength,
+ IN PVOID DisconnectInformation,
+ IN ULONG DisconnectIndicators
+
+Return Value:
+
+ NTSTATUS - Status of event indicator
+
+--*/
+
+{
+
+ NTSTATUS status;
+ tDEVICECONTEXT *pDeviceContext;
+
+ // convert the context value into the device context record ptr
+ pDeviceContext = (tDEVICECONTEXT *)EventContext;
+
+ IF_DBG(NBT_DEBUG_TDIHNDLR)
+ KdPrint(("pDeviceContxt = %X ConnectEv = %X\n",pDeviceContext,ConnectionContext));
+ ASSERTMSG("Bad Device context passed to the Connection Event Handler",
+ pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+
+ // call the non-OS specific routine to find a free connection.
+
+ status = DisconnectHndlrNotOs(
+ EventContext,
+ ConnectionContext,
+ DisconnectDataLength,
+ pDisconnectData,
+ DisconnectInformationLength,
+ pDisconnectInformation,
+ DisconnectIndicators);
+
+ if (!NT_SUCCESS(status))
+ {
+ IF_DBG(NBT_DEBUG_TDIHNDLR)
+ KdPrint(("NO FREE CONNECTIONS in connect handler\n"));
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+
+ return status;
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiRcvDatagramHandler(
+ IN PVOID pDgramEventContext,
+ IN int SourceAddressLength,
+ IN PVOID pSourceAddress,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN ULONG ReceiveDatagramFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *pBytesTaken,
+ IN PVOID pTsdu,
+ OUT PIRP *pIoRequestPacket
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive datagram event indication handler.
+
+ It is called when an Datagram arrives from the network, it will look for a
+ the address with an appropriate read datagram outstanding or a Datagrm
+ Event handler setup.
+
+Arguments:
+
+ pDgramEventContext - Context provided for this event - pab
+ SourceAddressLength, - length of the src address
+ pSourceAddress, - src address
+ OptionsLength, - options length for the receive
+ pOptions, - options
+ BytesIndicated, - number of bytes this indication
+ BytesAvailable, - number of bytes in complete Tsdu
+ pTsdu - pointer to the datagram
+
+
+Return Value:
+
+ *pBytesTaken - number of bytes used
+ *IoRequestPacket - Receive IRP if MORE_PROCESSING_REQUIRED.
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)pDgramEventContext;
+ tDGRAMHDR UNALIGNED *pDgram = (tDGRAMHDR UNALIGNED *)pTsdu;
+ PIRP pIrp = NULL;
+ ULONG lBytesTaken;
+ tCLIENTLIST *pClientList;
+
+
+
+ IF_DBG(NBT_DEBUG_TDIHNDLR)
+ KdPrint(( "NBT receive datagram handler pDeviceContext: %X\n",
+ pDeviceContext ));
+
+ *pIoRequestPacket = NULL;
+
+ ASSERTMSG("NBT:Invalid Device Context passed to DgramRcv Handler!!\n",
+ pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
+
+ // call a non-OS specific routine to decide what to do with the datagrams
+ pIrp = NULL;
+ pClientList = NULL;
+ status = DgramHndlrNotOs(
+ pDgramEventContext,
+ SourceAddressLength,
+ pSourceAddress,
+ OptionsLength,
+ pOptions,
+ ReceiveDatagramFlags,
+ BytesIndicated,
+ BytesAvailable,
+ &lBytesTaken,
+ pTsdu,
+ (PVOID *)&pIrp,
+ &pClientList);
+
+
+ if ( !NT_SUCCESS(status) )
+ {
+ // fail the request back to the transport provider since we
+ // could not find a receive buffer or receive handler or the
+ // data was taken in the indication handler.
+ //
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ }
+ else
+ {
+ // a rcv buffer was returned, so use it for the receive.(an Irp)
+ PTDI_REQUEST_KERNEL_RECEIVEDG pParams;
+ PIO_STACK_LOCATION pIrpSp;
+ ULONG lRcvLength;
+ ULONG lRcvFlags;
+
+ // When the client list is returned, we need to make up an irp to
+ // send down to the transport, which we will use in the completion
+ // routine to copy the data to all clients, ONLY if we are not
+ // using a client buffer, so check that flag first.
+ //
+ if (pClientList && !pClientList->fUsingClientBuffer)
+ {
+ PMDL pMdl;
+ PVOID pBuffer;
+
+ //
+ // get an irp to do the receive with and attach
+ // a buffer to it.
+ //
+ status = GetIrp(&pIrp);
+
+ if (!NT_SUCCESS(status))
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ //
+ // make an Mdl for a buffer to get all of the data from
+ // the transprot
+ //
+ pBuffer = NbtAllocMem(BytesAvailable,NBT_TAG('t'));
+
+ pMdl = NULL;
+ if (pBuffer)
+ {
+ // Allocate a MDL and set the header sizes correctly
+ pMdl = IoAllocateMdl(
+ pBuffer,
+ BytesAvailable,
+ FALSE,
+ FALSE,
+ NULL);
+
+ }
+ if (!pMdl)
+ {
+ REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+ if (pBuffer)
+ CTEMemFree(pBuffer);
+
+ //ASSERT(pMdl);
+ KdPrint(("Nbt:Unable to get Mdl, Kill Connection\n"));
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ // Map the pages in memory...
+ MmBuildMdlForNonPagedPool(pMdl);
+ pIrp->MdlAddress = pMdl;
+ ASSERT(pMdl);
+
+ lRcvFlags = 0;
+
+ lRcvLength = BytesAvailable;
+ }
+ else
+ {
+ ASSERT(pIrp);
+ // *TODO* may have to keep track of the case where the
+ // client returns a buffer that is not large enough for all of the
+ // data indicated. So the next posting of a buffer gets passed
+ // directly to the transport.
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ lRcvFlags =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters)->ReceiveFlags;
+
+ lRcvLength = ((PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters)->ReceiveLength;
+
+ if (lRcvLength < BytesIndicated - lBytesTaken)
+ {
+ IF_DBG(NBT_DEBUG_TDIHNDLR)
+ KdPrint(("Nbt:Clients Buffer is too short on Rcv Dgram size= %X, needed = %X\n",
+ lRcvLength, BytesIndicated-lBytesTaken));
+ }
+ }
+
+
+ // this code is sped up somewhat by expanding the code here rather than calling
+ // the TdiBuildReceive macro
+ // make the next stack location the current one. Normally IoCallDriver
+ // would do this but we are not going through IoCallDriver here, since the
+ // Irp is just passed back with RcvIndication.
+ ASSERT(pIrp->CurrentLocation > 1);
+ IoSetNextIrpStackLocation(pIrp);
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pIrpSp->CompletionRoutine = CompletionRcvDgram;
+
+ // pass the ClientList to the completion routine so it can
+ // copy the datagram to several clients that may be listening on the
+ // same name
+ //
+ pIrpSp->Context = (PVOID)pClientList;
+ CHECK_PTR(pIrpSp);
+ pIrpSp->Flags = 0;
+
+ // set flags so the completion routine is always invoked.
+ pIrpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
+
+ pIrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ pIrpSp->MinorFunction = TDI_RECEIVE_DATAGRAM;
+ pIrpSp->DeviceObject = pDeviceContext->pDgramDeviceObject;
+ pIrpSp->FileObject = pDeviceContext->pDgramFileObject;
+
+ pParams = (PTDI_REQUEST_KERNEL_RECEIVEDG)&pIrpSp->Parameters;
+ pParams->ReceiveFlags = lRcvFlags;
+ pParams->ReceiveLength = lRcvLength;
+
+ // pass back the irp to the transport provider and increment the stack
+ // location so it can write to the irp if it needs to.
+ *pIoRequestPacket = pIrp;
+ *pBytesTaken = lBytesTaken;
+
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+
+ }
+
+ //
+ // Transport will complete the processing of the request, we don't
+ // want the datagram.
+ //
+
+ IF_DBG (NBT_DEBUG_TDIHNDLR)
+ KdPrint(( "NBT receive datagram handler ignored receive, pDeviceContext: %X\n",
+ pDeviceContext ));
+
+ return STATUS_DATA_NOT_ACCEPTED;
+
+ // to keep the compiler from generating warnings...
+ UNREFERENCED_PARAMETER( SourceAddressLength );
+ UNREFERENCED_PARAMETER( BytesIndicated );
+ UNREFERENCED_PARAMETER( BytesAvailable );
+ UNREFERENCED_PARAMETER( pBytesTaken );
+ UNREFERENCED_PARAMETER( pTsdu );
+ UNREFERENCED_PARAMETER( OptionsLength );
+ UNREFERENCED_PARAMETER( pOptions );
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiRcvNameSrvHandler(
+ IN PVOID pDgramEventContext,
+ IN int SourceAddressLength,
+ IN PVOID pSourceAddress,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN ULONG ReceiveDatagramFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *pBytesTaken,
+ IN PVOID pTsdu,
+ OUT PIRP *pIoRequestPacket
+ )
+/*++
+
+Routine Description:
+
+ This routine is the Name Service datagram event indication handler.
+ It gets all datagrams destined for UDP port 137
+
+
+Arguments:
+
+ pDgramEventContext - Context provided for this event - pab
+ SourceAddressLength, - length of the src address
+ pSourceAddress, - src address
+ OptionsLength, - options length for the receive
+ pOptions, - options
+ BytesIndicated, - number of bytes this indication
+ BytesAvailable, - number of bytes in complete Tsdu
+ pTsdu - pointer to the datagram
+
+
+Return Value:
+
+ *pBytesTaken - number of bytes used
+ *IoRequestPacket - Receive IRP if MORE_PROCESSING_REQUIRED.
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)pDgramEventContext;
+ tNAMEHDR UNALIGNED *pNameSrv = (tNAMEHDR UNALIGNED *)pTsdu;
+ USHORT OpCode;
+
+
+ IF_DBG(NBT_DEBUG_TDIHNDLR)
+ KdPrint(( "NBT: NAMEHDR datagram handler pDeviceContext: %X\n",
+ pDeviceContext ));
+
+ *pIoRequestPacket = NULL;
+ //
+ // check if the whole datagram has arrived yet
+ //
+ if (BytesIndicated != BytesAvailable)
+ {
+ PIRP pIrp;
+ PVOID pBuffer;
+ PMDL pMdl;
+ ULONG Length;
+
+ //
+ // get an irp to do the receive with and attach
+ // a buffer to it.
+ //
+ status = GetIrp(&pIrp);
+
+ if (!NT_SUCCESS(status))
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ //
+ // make an Mdl for a buffer to get all of the data from
+ // the transprot
+ //
+ Length = BytesAvailable + SourceAddressLength + sizeof(ULONG);
+ Length = ((Length + 3)/sizeof(ULONG)) * sizeof(ULONG);
+ pBuffer = NbtAllocMem(Length,NBT_TAG('u'));
+ if (pBuffer)
+ {
+ PVOID pSrcAddr;
+
+ //
+ // save the source address and length in the buffer for later
+ // indication back to this routine.
+ //
+ *(ULONG UNALIGNED *)((PUCHAR)pBuffer + BytesAvailable) = SourceAddressLength;
+ pSrcAddr = (PVOID)((PUCHAR)pBuffer + BytesAvailable + sizeof(ULONG));
+
+ CTEMemCopy(pSrcAddr,
+ pSourceAddress,
+ SourceAddressLength);
+
+ // Allocate a MDL and set the header sizes correctly
+ pMdl = IoAllocateMdl(
+ pBuffer,
+ BytesAvailable,
+ FALSE,
+ FALSE,
+ NULL);
+
+ if (pMdl)
+ {
+ // Map the pages in memory...
+ MmBuildMdlForNonPagedPool(pMdl);
+ pIrp->MdlAddress = pMdl;
+ ASSERT(pMdl);
+
+ TdiBuildReceive(
+ pIrp,
+ &pDeviceContext->DeviceObject,
+ pDeviceContext->pNameServerFileObject,
+ NameSrvCompletionRoutine,
+ (PVOID)BytesAvailable,
+ pMdl,
+ (ULONG)TDI_RECEIVE_NORMAL,
+ BytesAvailable);
+
+ *pBytesTaken = 0;
+
+ *pIoRequestPacket = pIrp;
+
+ // make the next stack location the current one. Normally IoCallDriver
+ // would do this but we are not going through IoCallDriver here, since the
+ // Irp is just passed back with RcvIndication.
+ //
+ ASSERT(pIrp->CurrentLocation > 1);
+ IoSetNextIrpStackLocation(pIrp);
+
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+ }
+
+
+ }
+
+ // put our Irp back on its free list
+ //
+ REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ }
+
+ if (pWinsInfo)
+ {
+ USHORT TransactionId;
+ ULONG SrcAddress;
+
+ SrcAddress = ntohl(((PTDI_ADDRESS_IP)&((PTRANSPORT_ADDRESS)pSourceAddress)->Address[0].Address[0])->in_addr);
+ //
+ // Pass To Wins if:
+ //
+ // 1) It is a response pdu with the transaction id in the WINS range
+ // that is not a WACK... OR
+ // 2) It is a request that is NOT broadcast....and...
+ // 2) It is a name query(excluding node status requests),
+ // Allowing queries from other netbt clients
+ // allowing queries from anyone not on this machine OR
+ // 3) It is a name release request. OR
+ // 4) It is a name refresh OR
+ // 5) It is a name registration
+ //
+ OpCode = pNameSrv->OpCodeFlags;
+ TransactionId = ntohs(pNameSrv->TransactId);
+
+ if (((OpCode & OP_RESPONSE) &&
+ (TransactionId <= WINS_MAXIMUM_TRANSACTION_ID) &&
+ (OpCode != OP_WACK))
+ ||
+ (!(OpCode & (OP_RESPONSE | FL_BROADCAST)) &&
+ (
+ (((OpCode & NM_FLAGS_MASK) == OP_QUERY) &&
+ (OpCode & FL_RECURDESIRE) && // not node status request
+ ((TransactionId > WINS_MAXIMUM_TRANSACTION_ID) ||
+ ( !SrcIsUs(SrcAddress) )))
+// (SrcAddress != pDeviceContext->lNameServerAddress )))
+ ||
+ (OpCode & (OP_RELEASE | OP_REFRESH))
+ ||
+ (OpCode & OP_REGISTRATION) )) )
+ {
+ status = PassNamePduToWins(
+ pDeviceContext,
+ pSourceAddress,
+ pNameSrv,
+ BytesIndicated);
+
+// NbtConfig.DgramBytesRcvd += BytesIndicated;
+
+ //
+ // if WINS took the data then tell the transport to dump the data
+ // since we have buffered it already. Otherwise, let nbt take
+ // a look at the data
+ //
+ if (NT_SUCCESS(status))
+ {
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ }
+ }
+
+ {
+
+ // DO a quick check of the name to see if it is in the local name table
+ // and reject it otherwise - for name queries only, if not the proxy
+ //
+ if ((BytesIndicated >= NBT_MINIMUM_QUERY) && !(NodeType & PROXY))
+ {
+ ULONG UNALIGNED *pHdr;
+ ULONG i,lValue;
+ UCHAR pNameStore[NETBIOS_NAME_SIZE];
+ UCHAR *pName;
+ tNAMEADDR *pNameAddr;
+ CTELockHandle OldIrq;
+
+ // it must be a name query request, not a response, and not a
+ // node status request, to enter this special check
+ //
+ OpCode = pNameSrv->OpCodeFlags;
+ if (((OpCode & NM_FLAGS_MASK) == OP_QUERY) &&
+ (!(OpCode & OP_RESPONSE)) &&
+ (OpCode & FL_RECURDESIRE)) // not node status request
+ {
+ pHdr = (ULONG UNALIGNED *)pNameSrv->NameRR.NetBiosName;
+ pName = pNameStore;
+
+ // the Half Ascii portion of the netbios name is always 32 bytes long
+ for (i=0; i < NETBIOS_NAME_SIZE*2 ;i +=4 )
+ {
+ lValue = *pHdr - 0x41414141; // four A's
+ pHdr++;
+ lValue = ((lValue & 0x0F000000) >> 16) +
+ ((lValue & 0x0F0000) >> 4) +
+ ((lValue & 0x0F00) >> 8) +
+ ((lValue & 0x0F) << 4);
+ *(PUSHORT)pName = (USHORT)lValue;
+ ((PUSHORT)pName)++;
+
+ }
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ status = FindInHashTable(NbtConfig.pLocalHashTbl,
+ pNameStore,
+ NULL,
+ &pNameAddr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ if (!NT_SUCCESS(status))
+ {
+ *pBytesTaken = BytesIndicated;
+ return(STATUS_DATA_NOT_ACCEPTED);
+ }
+ }
+ }
+
+
+ // call a non-OS specific routine to decide what to do with the datagrams
+ status = NameSrvHndlrNotOs(
+ pDeviceContext,
+ pSourceAddress,
+ pNameSrv,
+ BytesIndicated,
+ (BOOLEAN)((ReceiveDatagramFlags & TDI_RECEIVE_BROADCAST) != 0));
+
+// NbtConfig.DgramBytesRcvd += BytesIndicated
+
+ }
+
+ return status;
+
+ // to keep the compiler from generating warnings...
+ UNREFERENCED_PARAMETER( SourceAddressLength );
+ UNREFERENCED_PARAMETER( BytesIndicated );
+ UNREFERENCED_PARAMETER( BytesAvailable );
+ UNREFERENCED_PARAMETER( pBytesTaken );
+ UNREFERENCED_PARAMETER( pTsdu );
+ UNREFERENCED_PARAMETER( OptionsLength );
+ UNREFERENCED_PARAMETER( pOptions );
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+NameSrvCompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the case when a name service datagram is too
+ short and and Irp has to be passed back to the transport to get the
+ rest of the datagram. The irp completes through here when full.
+
+Arguments:
+
+ DeviceObject - unused.
+
+ Irp - Supplies Irp that the transport has finished processing.
+
+ Context - Supplies the pConnectEle - the connection data structure
+
+Return Value:
+
+ The final status from the operation (success or an exception).
+
+--*/
+{
+ NTSTATUS status;
+ PIRP pIoRequestPacket;
+ ULONG BytesTaken;
+ ULONG Offset = (ULONG)Context;
+ PVOID pBuffer;
+ ULONG SrcAddressLength;
+ PVOID pSrcAddress;
+
+
+ IF_DBG (NBT_DEBUG_TDIHNDLR)
+ KdPrint(("NameSrvCompletionRoutine pRcvBuffer: %X, Status: %X Length %X\n",
+ Context,
+ pIrp->IoStatus.Status,
+ pIrp->IoStatus.Information ));
+
+ pBuffer = MmGetSystemAddressForMdl(pIrp->MdlAddress);
+
+ SrcAddressLength = *(ULONG UNALIGNED *)((PUCHAR)pBuffer + Offset);
+ pSrcAddress = (PVOID)((PUCHAR)pBuffer + Offset + sizeof(ULONG));
+ //
+ // just call the regular indication routine as if UDP had done it.
+ //
+ TdiRcvNameSrvHandler(
+ DeviceObject,
+ SrcAddressLength,
+ pSrcAddress,
+ 0,
+ NULL,
+ TDI_RECEIVE_NORMAL,
+ pIrp->IoStatus.Information,
+ pIrp->IoStatus.Information,
+ &BytesTaken,
+ pBuffer,
+ &pIoRequestPacket );
+
+ CTEMemFree(MmGetSystemAddressForMdl(pIrp->MdlAddress));
+
+ IoFreeMdl(pIrp->MdlAddress);
+
+ // put our Irp back on its free list
+ //
+ REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+CompletionRcvDgram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This routine completes the Irp by removing the Rcv Element off the queue
+ and putting it back on the free list.
+
+Arguments:
+
+ DeviceObject - unused.
+
+ Irp - Supplies Irp that the transport has finished processing.
+
+ Context - Supplies the pConnectEle - the connection data structure
+
+Return Value:
+
+ The final status from the operation (success or an exception).
+
+--*/
+{
+ NTSTATUS status;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PVOID pRemoteAddress;
+ ULONG RemoteAddressLength;
+ ULONG BytesCopied;
+ PVOID pTsdu;
+ ULONG ReceiveFlags;
+ tCLIENTLIST *pClientList;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq2;
+ ULONG ClientBytesTaken;
+ ULONG DataLength;
+ tADDRESSELE *pAddress;
+ tRCVELE *pRcvEle;
+ PLIST_ENTRY pRcvEntry;
+ tDEVICECONTEXT *pDeviceContext;
+ CTEULONGLONG AdapterNumber;
+
+
+
+ IF_DBG (NBT_DEBUG_TDIHNDLR)
+ KdPrint(("CompletionRcvDgram pRcvBuffer: %X, Status: %X Length %X\n",
+ Context,
+ Irp->IoStatus.Status,
+ Irp->IoStatus.Information ));
+
+
+ // there may be several clients that want to see this datagram so check
+ // the client list to see...
+ //
+ if (Context)
+ {
+ tCLIENTELE *pClientPrev = NULL;
+
+ DataLength = Irp->IoStatus.Information;
+
+ pTsdu = MmGetSystemAddressForMdl(Irp->MdlAddress);
+
+ pClientList = (tCLIENTLIST *)Context;
+
+ // for the multihomed host, we only want to distribute the inbound
+ // datagram to clients on this same adapter, to avoid giving the
+ // datagram to the same client several times, once for each adapter
+ // it is bound to.
+ //
+ pDeviceContext = pClientList->pClientEle->pDeviceContext;
+ AdapterNumber = pDeviceContext->AdapterNumber;
+
+ pAddress = pClientList->pAddress;
+ pRemoteAddress = pClientList->pRemoteAddress;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pHead = &pClientList->pAddress->ClientHead;
+ pEntry = pHead->Flink;
+ RemoteAddressLength = pClientList->RemoteAddressLength;
+ ReceiveFlags = pClientList->ReceiveDatagramFlags;
+
+#ifdef PROXY_NODE
+ if (!pClientList->fProxy)
+ {
+#endif
+ if (!pClientList->fUsingClientBuffer)
+ {
+
+ while (pEntry != pHead)
+ {
+ PTDI_IND_RECEIVE_DATAGRAM EvRcvDgram;
+ PVOID RcvDgramEvContext;
+ tCLIENTELE *pClientEle;
+ PIRP pRcvIrp;
+
+
+ pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
+
+ // for multihomed hosts only distribute the datagram to
+ // clients hooked to this device context to avoid duplicate
+ // indications
+ //
+ if (pClientEle->pDeviceContext->AdapterNumber == AdapterNumber)
+ {
+ InterlockedIncrement(&pClientEle->RefCount);
+
+ EvRcvDgram = pClientEle->evRcvDgram;
+ RcvDgramEvContext = pClientEle->RcvDgramEvContext;
+
+ CTESpinFree(&NbtConfig.JointLock, OldIrq);
+
+ // dereference the previous client in the list
+ if (pClientPrev)
+ {
+ NbtDereferenceClient(pClientPrev);
+ }
+
+ pRcvIrp = NULL;
+
+ ClientBytesTaken = 0;
+
+ status = (*EvRcvDgram)(RcvDgramEvContext,
+ RemoteAddressLength,
+ pRemoteAddress,
+ 0,
+ NULL,
+ #ifndef VXD
+ ReceiveFlags,
+ #endif
+ DataLength,
+ DataLength,
+ &ClientBytesTaken,
+ pTsdu,
+ &pRcvIrp);
+
+ if (!pRcvIrp)
+ {
+ // if no buffer is returned, then the client is done
+ // with the data so go to the next client ...since it may
+ // be possible to process all clients in this loop without
+ // ever sending an irp down to the transport
+ // free the remote address mem block
+
+ status = STATUS_DATA_NOT_ACCEPTED;
+ }
+ else
+ {
+
+ // the client has passed back an irp so
+ // copy the data to the client's Irp
+ //
+ TdiCopyBufferToMdl(pTsdu,
+ ClientBytesTaken,
+ DataLength - ClientBytesTaken,
+ pRcvIrp->MdlAddress,
+ 0,
+ &BytesCopied);
+
+ // length is copied length (since the MDL may be
+ // too short to take it all)
+ //
+ if (BytesCopied < (DataLength-ClientBytesTaken))
+ {
+ pRcvIrp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+
+ }
+ else
+ {
+ pRcvIrp->IoStatus.Status = STATUS_SUCCESS;
+ }
+
+ pRcvIrp->IoStatus.Information = BytesCopied;
+
+ IoCompleteRequest(pRcvIrp,IO_NETWORK_INCREMENT);
+ }
+
+ CTESpinLock(&NbtConfig.JointLock, OldIrq);
+
+
+ pClientPrev = pClientEle;
+ }
+ // this code is protected from a client removing itself
+ // from the list of clients attached to an address by
+ // referencing the client prior to releasing the spin lock
+ // on the address. The client element does not get
+ // removed from the address list until its ref count goes
+ // to zero. We must hold the joint spin lock to prevent the
+ // next client from deleting itself from the list before we
+ // can increment its reference count.
+ //
+ pEntry = pEntry->Flink;
+
+
+ } // of while(pEntry != pHead)
+
+
+ }
+ else
+ {
+ // *** Client Has posted a receive Buffer, rather than using
+ // *** receive handler - VXD case!
+ // ***
+ while (pEntry != pHead)
+ {
+ tCLIENTELE *pClientEle;
+ PIRP pRcvIrp;
+
+ pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
+
+ // for multihomed hosts only distribute the datagram to
+ // clients hooked to this device context to avoid duplicate
+ // indications
+ //
+ if (pClientEle->pDeviceContext->AdapterNumber == AdapterNumber)
+ {
+ InterlockedIncrement(&pClientEle->RefCount);
+
+ // check for datagrams posted to this name
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ // undo the InterlockedIncrement on the refcount
+ if (pClientPrev)
+ {
+ NbtDereferenceClient(pClientPrev);
+ pClientPrev = NULL;
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (pClientEle == pClientList->pClientEle)
+ {
+ // this is the client whose buffer we are using - it is
+ // passed up to the client after all other clients
+ // have been processed.
+ //
+ InterlockedDecrement(&pClientEle->RefCount);
+ pEntry = pEntry->Flink;
+ continue;
+ }
+ else
+ if (!IsListEmpty(&pClientEle->RcvDgramHead))
+ {
+
+ pRcvEntry = RemoveHeadList(&pClientEle->RcvDgramHead);
+ pRcvEle = CONTAINING_RECORD(pRcvEntry,tRCVELE,Linkage);
+ pRcvIrp = pRcvEle->pIrp;
+
+ //
+ // copy the data to the client's Irp
+ //
+ TdiCopyBufferToMdl(pTsdu,
+ 0,
+ DataLength,
+ pRcvIrp->MdlAddress,
+ 0,
+ &BytesCopied);
+
+ // length is copied length (since the MDL may be too short to take it all)
+ if (BytesCopied < DataLength)
+ {
+ pRcvIrp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
+
+ }
+ else
+ {
+ pRcvIrp->IoStatus.Status = STATUS_SUCCESS;
+ }
+
+ pRcvIrp->IoStatus.Information = BytesCopied;
+
+ CTESpinFree(&NbtConfig.JointLock, OldIrq);
+
+ IoCompleteRequest(pRcvIrp,IO_NETWORK_INCREMENT);
+
+
+ // free the receive block
+ CTEMemFree((PVOID)pRcvEle);
+
+ CTESpinLock(&NbtConfig.JointLock, OldIrq);
+ }
+
+ pEntry = pEntry->Flink;
+
+ pClientPrev = pClientEle;
+ }
+
+ } // of while(pEntry != pHead)
+
+ // free the remote address structure and the client list
+ // allocated in DgramHndlrNotOs
+ //
+ CTESpinFree(&NbtConfig.JointLock, OldIrq);
+
+ // undo the InterlockedIncrement on the refcount
+ if (pClientPrev)
+ {
+ NbtDereferenceClient(pClientPrev);
+ }
+ CTEMemFree(pClientList->pRemoteAddress);
+
+ //
+ // The address was referenced in DgramRcvNotOs to be sure it did not
+ // disappear until this dgram rcv was done, which is now.
+ //
+ NbtDereferenceAddress(pClientList->pAddress);
+
+ CTEMemFree(Context);
+
+
+ // returning success allows the IO subsystem to complete the
+ // irp that we used to get the data - i.e. one client's
+ // buffer
+ //
+ return(STATUS_SUCCESS);
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // dereference the previous client in the list from the RcvHANDLER
+ // case a page or so above...
+ //
+ if (pClientPrev)
+ {
+ NbtDereferenceClient(pClientPrev);
+ }
+
+ //
+ // The address was referenced in DgramRcvNotOs to be sure it did not
+ // disappear until this dgram rcv was done, which is now.
+ //
+ NbtDereferenceAddress(pClientList->pAddress);
+
+
+#ifdef PROXY_NODE
+ }
+ else
+ {
+ //
+ // Call the ProxyDoDgramDist after freeing the jointlock.
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = ProxyDoDgramDist(
+ pTsdu,
+ DataLength,
+ (tNAMEADDR *)pClientList->pAddress, //NameAddr
+ pClientList->pRemoteAddress //device context
+ );
+
+ }
+#endif
+
+
+ //
+ // Free the buffers allocated
+ //
+ CTEMemFree(pTsdu);
+ if (!pClientList->fProxy)
+ {
+ CTEMemFree(pClientList->pRemoteAddress);
+ }
+ CTEMemFree(Context);
+
+ IF_DBG(NBT_DEBUG_RCV)
+ KdPrint(("****Freeing Mdl: Irp = %X Mdl = %X\n",Irp,Irp->MdlAddress));
+ IoFreeMdl(Irp->MdlAddress);
+
+ // put our Irp back on its free list
+ //
+ REMOVE_FROM_LIST(&Irp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &Irp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+
+ }
+
+ // for the single receive case this passes the rcv up to the client
+ //
+ return(STATUS_SUCCESS);
+
+ UNREFERENCED_PARAMETER( DeviceObject );
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiErrorHandler (
+ IN PVOID Context,
+ IN NTSTATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called on any error indications passed back from the
+ transport. It implements LAN_STATUS_ALERT.
+
+Arguments:
+
+ Context - Supplies the pfcb for the address.
+
+ Status - Supplies the error.
+
+Return Value:
+
+ NTSTATUS - Status of event indication
+
+--*/
+
+{
+
+ // debug *JS
+ KdPrint(("Nbt: Error Event HAndler hit unexpectedly\n"));
+ return(STATUS_DATA_NOT_ACCEPTED);
+
+ return STATUS_SUCCESS;
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+SumMdlLengths (
+ IN PMDL pMdl,
+ IN ULONG BytesCopied,
+ IN tCONNECTELE *pConnectEle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to sum the lengths of MDLs in a chain.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - Status of event indication
+
+--*/
+
+{
+ ULONG TotalLength;
+
+ TotalLength = 0;
+
+ do
+ {
+ if ((TotalLength + MmGetMdlByteCount(pMdl)) > BytesCopied)
+ {
+ pConnectEle->OffsetFromStart = BytesCopied - TotalLength;
+ pConnectEle->pNextMdl = pMdl;
+ break;
+ }
+ else
+ {
+ TotalLength += MmGetMdlByteCount(pMdl);
+ }
+ }
+ while (pMdl=(PMDL)pMdl->Next);
+
+ return;
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+AllocateMdl (
+ IN tCONNECTELE *pConnEle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to allocate a Mdl for the Connection.
+
+Arguments:
+
+ pConnEle - ptr to the connection element
+
+Return Value:
+
+ NTSTATUS - Status of event indication
+
+--*/
+
+{
+ PMDL pNewMdl;
+ PVOID NewAddress;
+
+ //
+ // Allocate an extra MDL for this connection if there isn't one
+ // already allocated.
+ //
+ if (pConnEle->pNewMdl == NULL )
+ {
+ // The length of the
+ // Mdl is set to 64K(MAXUSHORT) so that there are enough pfns in the
+ // Mdl to map a large buffer.
+ //
+ // use the pConnEle as the Virtual address, since it doesn't matter
+ // because it will be overwritten when the partial Mdl is created.
+ //
+ NewAddress = pConnEle;
+ pNewMdl = IoAllocateMdl(
+ NewAddress,
+ MAXUSHORT,
+ FALSE,
+ FALSE,NULL);
+ if (!pNewMdl)
+ {
+ ASSERTMSG("Nbt:Unable to allocate a MDL!!\n",0);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ pConnEle->pNewMdl = pNewMdl;
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+MakePartialMdl (
+ IN tCONNECTELE *pConnEle,
+ IN PIRP pIrp,
+ IN ULONG ToCopy
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to build a partial Mdl that accounts for ToCopy
+ bytes of data being copied to the start of the Client's Mdl.
+
+Arguments:
+
+ pConnEle - ptr to the connection element
+
+Return Value:
+
+ NTSTATUS - Status of event indication
+
+--*/
+
+{
+ PMDL pNewMdl;
+ PVOID NewAddress;
+
+ // Build a partial Mdl to represent the client's Mdl chain since
+ // we have copied data to it, and the transport must copy
+ // more data to it after that data.
+ //
+ SumMdlLengths(pIrp->MdlAddress,ToCopy,pConnEle);
+
+ // this routine has set the Mdl that the next data starts at and
+ // the offset from the start of that Mdl, so create a partial Mdl
+ // to map that buffer and tack it on the mdl chain instead of the
+ // original
+ //
+ pNewMdl = pConnEle->pNewMdl;
+ NewAddress = (PVOID)((PUCHAR)MmGetMdlVirtualAddress(pConnEle->pNextMdl)
+ + pConnEle->OffsetFromStart);
+ IoBuildPartialMdl(pConnEle->pNextMdl,pNewMdl,NewAddress,0);
+
+ // hook the new partial mdl to the front of the MDL chain
+ //
+ pNewMdl->Next = pConnEle->pNextMdl->Next;
+
+ pIrp->MdlAddress = pNewMdl;
+ ASSERT(pNewMdl);
+}
+//----------------------------------------------------------------------------
+ VOID
+CopyToStartofIndicate (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN ULONG DataTaken
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to copy data remaining in the indicate buffer to
+ the head of the indicate buffer.
+
+Arguments:
+
+ pLowerConn - ptr to the lower connection element
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ PVOID pSrc;
+ ULONG DataLeft;
+ PVOID pMdl;
+
+
+ DataLeft = pLowerConn->BytesInIndicate;
+
+ pMdl = (PVOID)MmGetMdlVirtualAddress(pLowerConn->pIndicateMdl);
+
+ pSrc = (PVOID)( (PUCHAR)pMdl + DataTaken);
+
+ CTEMemCopy(pMdl,pSrc,DataLeft);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTProcessAcceptIrp(
+ IN PIRP pIrp,
+ OUT tCONNECTELE **ppConnEle)
+
+/*++
+Routine Description:
+
+ This Routine handles a Client's AcceptIrp, extracting the pConnEle and
+ returning it.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ PIO_STACK_LOCATION pIrpSp;
+ PTDI_REQUEST_KERNEL_ACCEPT pRequest;
+ tCONNECTELE *pConnEle;
+
+
+ // pull the junk out of the Irp and call the non-OS specific routine.
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ // the Parameters value points to a Request structure...
+ pRequest = (PTDI_REQUEST_KERNEL_ACCEPT)&pIrpSp->Parameters;
+
+ // the pConnEle ptr was stored in the FsContext value when the connection
+ // was initially created.
+ pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
+
+ *ppConnEle = pConnEle;
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+
+ NTSTATUS
+OutOfRsrcKill(
+ OUT tLOWERCONNECTION *pLowerConn)
+
+/*++
+Routine Description:
+
+ This Routine handles killing a connection when an out of resource condition
+ occurs. It uses a special Irp that it has saved away, and a linked list
+ if that irp is currently in use.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ CTELockHandle OldIrq1;
+ PIRP pIrp;
+ PFILE_OBJECT pFileObject;
+ PDEVICE_OBJECT pDeviceObject;
+ tDEVICECONTEXT *pDeviceContext = pLowerConn->pDeviceContext;
+
+
+ CTESpinLock(pDeviceContext,OldIrq);
+ CTESpinLock(&NbtConfig,OldIrq1);
+
+ InterlockedIncrement(&pLowerConn->RefCount);
+ if (NbtConfig.OutOfRsrc.pIrp)
+ {
+ // get an Irp to send the message in
+ pIrp = NbtConfig.OutOfRsrc.pIrp;
+ NbtConfig.OutOfRsrc.pIrp = NULL;
+
+ pFileObject = pLowerConn->pFileObject;
+ pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
+
+ CTESpinFree(&NbtConfig,OldIrq1);
+ CTESpinFree(pDeviceContext,OldIrq);
+
+ // store some context stuff in the Irp stack so we can call the completion
+ // routine set by the Udpsend code...
+ TdiBuildDisconnect(
+ pIrp,
+ pDeviceObject,
+ pFileObject,
+ RsrcKillCompletion,
+ pLowerConn, //context value passed to completion routine
+ NULL, // Timeout...
+ TDI_DISCONNECT_ABORT,
+ NULL, // send connection info
+ NULL); // return connection info
+
+ CHECK_PTR(pIrp);
+ pIrp->MdlAddress = NULL;
+
+ CHECK_COMPLETION(pIrp);
+ status = IoCallDriver(pDeviceObject,pIrp);
+
+ IF_DBG(NBT_DEBUG_REF)
+ KdPrint(("Nbt:Out of Resource, Kill connection, %X\n",pLowerConn));
+
+ return(status);
+
+ }
+ else
+ {
+ //
+ // The lower conn could get removed here, then get dequed from the ConnectionHead and come here
+ // (via DpcNextOutOfRsrcKill), and fail to get an Irp; we re-enque it into the OutOfRsrc list,
+ // but should not try to deque it here.
+ //
+ if (!pLowerConn->OutOfRsrcFlag) {
+
+ RemoveEntryList(&pLowerConn->Linkage);
+
+ //
+ // The lower conn gets removed from the inactive list here and again when CleanupAfterDisconnect
+ // calls NbtDeleteLowerConn. In order to prevent the second deque, we set a flag here and test
+ // for it in NbtDeleteLowerConn.
+ //
+ pLowerConn->OutOfRsrcFlag = TRUE;
+ }
+
+ pLowerConn->Linkage.Flink = pLowerConn->Linkage.Blink = (struct _LIST_ENTRY * volatile)0x00006041;
+ InsertTailList(&NbtConfig.OutOfRsrc.ConnectionHead,&pLowerConn->Linkage);
+
+ CTESpinFree(&NbtConfig,OldIrq1);
+ CTESpinFree(pDeviceContext,OldIrq);
+ }
+
+ return(STATUS_SUCCESS);
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+RsrcKillCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion of a disconnect to the transport.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ NTSTATUS status;
+ KIRQL OldIrq;
+ PLIST_ENTRY pEntry;
+ tLOWERCONNECTION *pLowerConn;
+ PKDPC pDpc;
+
+
+
+ pLowerConn = (tLOWERCONNECTION *)pContext;
+
+ // this call will indicate the disconnect to the client and clean up
+ // abit.
+ //
+ status = DisconnectHndlrNotOs (
+ NULL,
+ (PVOID)pLowerConn,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ TDI_DISCONNECT_ABORT);
+
+ NbtDereferenceLowerConnection(pLowerConn);
+
+ CTESpinLock(&NbtConfig,OldIrq);
+ NbtConfig.OutOfRsrc.pIrp = pIrp;
+
+ if (!IsListEmpty(&NbtConfig.OutOfRsrc.ConnectionHead))
+ {
+ if (NbtConfig.OutOfRsrc.pDpc)
+ {
+ pDpc = NbtConfig.OutOfRsrc.pDpc;
+ NbtConfig.OutOfRsrc.pDpc = NULL;
+
+ pEntry = RemoveHeadList(&NbtConfig.OutOfRsrc.ConnectionHead);
+ pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
+
+ pLowerConn->Linkage.Flink = pLowerConn->Linkage.Blink = (struct _LIST_ENTRY * volatile)0x00006109;
+ KeInitializeDpc(pDpc,
+ DpcNextOutOfRsrcKill,
+ (PVOID)pLowerConn);
+
+ KeInsertQueueDpc(pDpc,NULL,NULL);
+
+ CTESpinFree(&NbtConfig,OldIrq);
+
+ }
+ else
+ CTESpinFree(&NbtConfig,OldIrq);
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig,OldIrq);
+ }
+
+
+
+ //
+ // return this status to stop the IO subsystem from further processing the
+ // IRP - i.e. trying to complete it back to the initiating thread! -since
+ // there is no initiating thread - we are the initiator
+ //
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+DpcNextOutOfRsrcKill(
+ IN PKDPC pDpc,
+ IN PVOID Context,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+/*++
+
+Routine Description:
+
+ This routine simply calls OutOfRsrcKill from a Dpc started in
+ RsrcKillCompletion.
+
+Arguments:
+
+
+Return Value:
+--*/
+{
+
+ KIRQL OldIrq;
+ tLOWERCONNECTION *pLowerConn;
+
+
+ pLowerConn = (tLOWERCONNECTION *)Context;
+
+ CTESpinLock(&NbtConfig,OldIrq);
+ NbtConfig.OutOfRsrc.pDpc = pDpc;
+ CTESpinFree(&NbtConfig,OldIrq);
+
+ OutOfRsrcKill(pLowerConn);
+
+ //
+ // to remove the extra reference put on pLowerConn when OutOfRsrc called
+ //
+ NbtDereferenceLowerConnection(pLowerConn);
+
+}
+
+
+//----------------------------------------------------------------------------
+ VOID
+FillIrpCancelRoutine(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a Receive Irp that has been saved
+ during the FILL_IRP state. It must release the
+ cancel spin lock before returning re: IoCancelIrp().
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ tCONNECTELE *pConnEle;
+ KIRQL OldIrq;
+ KIRQL OldIrq1;
+ KIRQL OldIrq2;
+ PIO_STACK_LOCATION pIrpSp;
+ tLOWERCONNECTION *pLowerConn;
+ BOOLEAN CompleteIt = FALSE;
+
+ IF_DBG(NBT_DEBUG_INDICATEBUFF)
+ KdPrint(("Nbt:Got a Receive Cancel Irp !!! *****************\n"));
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ pConnEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+
+ // now look for an Irp to cancel
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+ CTESpinLock(pConnEle,OldIrq);
+
+
+ pLowerConn = pConnEle->pLowerConnId;
+ if (pLowerConn)
+ {
+ CTESpinLock(pLowerConn,OldIrq2);
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+ SetStateProc(pLowerConn,RejectAnyData);
+
+ }
+
+
+ CHECK_PTR(pConnEle);
+
+ pConnEle->pIrpRcv = NULL;
+
+
+ if (pLowerConn)
+ {
+ CTESpinFree(pLowerConn,OldIrq2);
+ }
+
+ CTESpinFree(pConnEle,OldIrq);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // complete the irp
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ if (pLowerConn)
+ {
+ //
+ // Cancelling a Rcv Irp in the fill irp state will cause netbt
+ // to lose track of where it is in the message so it must kill
+ // the connection.
+ //
+ OutOfRsrcKill(pLowerConn);
+ }
+ return;
+
+}
+
+
diff --git a/private/ntos/nbt/nt/tdiout.c b/private/ntos/nbt/nt/tdiout.c
new file mode 100644
index 000000000..da98a8850
--- /dev/null
+++ b/private/ntos/nbt/nt/tdiout.c
@@ -0,0 +1,727 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Tdiout.c
+
+Abstract:
+
+
+ This file represents the TDI interface on the bottom edge of NBT.
+ The procedures herein conform to the TDI I/F spec. and then convert
+ the information to NT specific Irps etc. This implementation can be
+ changed out to run on another OS.
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+
+#include "nbtprocs.h" // procedure headings
+
+// function prototypes for completion routines used in this file
+NTSTATUS
+DgramSendComplete(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ );
+NTSTATUS
+TcpConnectComplete(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ );
+NTSTATUS
+TcpDisconnectComplete(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ );
+NTSTATUS
+SendSessionCompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ );
+
+// DEBUG
+VOID
+CheckIrpList(
+ );
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiSendDatagram(
+ IN PTDI_REQUEST pRequestInfo,
+ IN PTDI_CONNECTION_INFORMATION pSendDgramInfo,
+ IN ULONG SendLength,
+ OUT PULONG pSentSize,
+ IN tBUFFER *pSendBuffer,
+ IN ULONG SendFlags
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a datagram to the transport
+
+Arguments:
+
+ pSendBuffer - this is really an Mdl in NT land. It must be tacked on
+ the end of the Mdl created for the Nbt datagram header.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ PIRP pRequestIrp;
+ PMDL pMdl;
+ PDEVICE_OBJECT pDeviceObject;
+ PFILE_OBJECT pFileObject;
+ PVOID pCompletionRoutine;
+
+ // get an Irp to send the message in
+ pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
+ pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
+
+ // get an Irp from the list
+ status = GetIrp(&pRequestIrp);
+
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("Nbt:Failed to get an Irp in TdiSendDatagram"));
+
+ // call the completion routine with this status (if there is one)
+ if (pRequestInfo->RequestNotifyObject)
+ {
+ (*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
+ ((PVOID)pRequestInfo->RequestContext,
+ STATUS_INSUFFICIENT_RESOURCES,
+ 0L);
+ }
+
+ // so the Irp is not completed twice.
+ return(STATUS_PENDING);
+ }
+
+ pRequestIrp->CancelRoutine = NULL;
+
+ // set up the completion routine passed in from Udp Send using the APC
+ // fields in the Irp that would normally be used to complete the request
+ // back to the client - although we are really the client here so we can
+ // use these fields our self!
+ pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
+ (PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
+ pRequestIrp->Overlay.AsynchronousParameters.UserApcContext =
+ (PVOID)pRequestInfo->RequestContext;
+
+ // Allocate a MDL and set the head sizes correctly
+ pMdl = IoAllocateMdl(
+ pSendBuffer->pDgramHdr,
+ pSendBuffer->HdrLength,
+ FALSE,
+ FALSE,
+ NULL);
+
+ if (!pMdl)
+ {
+ REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pRequestIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+ if (pRequestInfo->RequestNotifyObject)
+ {
+ // call the completion routine will this status
+ (*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
+ ((PVOID)pRequestInfo->RequestContext,
+ STATUS_INSUFFICIENT_RESOURCES,
+ 0L);
+ }
+ ASSERT(pMdl);
+ return(STATUS_PENDING);
+ }
+
+ // Map the pages in memory...
+ MmBuildMdlForNonPagedPool(pMdl);
+
+
+ pCompletionRoutine = DgramSendComplete;
+
+ // store some context stuff in the Irp stack so we can call the completion
+ // routine set by the Udpsend code...
+ TdiBuildSendDatagram(
+ pRequestIrp,
+ pDeviceObject,
+ pFileObject,
+ pCompletionRoutine,
+ NULL, //context value passed to completion routine
+ pMdl,
+ SendLength,
+ pSendDgramInfo);
+
+ // tack the client's send buffer (MDL) onto the end of the datagram header
+ // Mdl, and then pass the irp on downward to the transport
+ if (pSendBuffer->pBuffer)
+ pMdl->Next = (PMDL)pSendBuffer->pBuffer;
+
+ CHECK_COMPLETION(pRequestIrp);
+ status = IoCallDriver(pDeviceObject,pRequestIrp);
+
+ // Fill in the SentSize
+ *pSentSize = SendLength;
+
+ // The transport always completes the IRP, so as long as the irp made it
+ // to the transport it got completed. The return code from the transport
+ // does not indicate if the irp was completed or not. The real status
+ // of the operation is in the Irp Iostatus return code.
+ // What we need to do is make sure NBT does not complete the irp AND the
+ // transport complete the Irp. Therefore this routine returns
+ // status pending if the Irp was passed to the transport, regardless of
+ // the return code from the transport. This return code signals the caller
+ // that the irp will be completed via the completion routine and the
+ // actual status of the send can be found in the Irpss IoStatus.Status
+ // variable.
+ //
+ // If the Caller of this routine gets a bad return code, they can assume
+ // that this routine failed to give the Irp to the transport and it
+ // is safe for them to complete the Irp themselves.
+ //
+ // If the Completion routine is set to null, then there is no danger
+ // of the irp completing twice and this routine will return the transport
+ // return code in that case.
+
+ if (pRequestInfo->RequestNotifyObject)
+ return(STATUS_PENDING);
+ else
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+DgramSendComplete(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion of a datagram send to the transport.
+ It must call the client completion routine and free the Irp and Mdl.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ KIRQL OldIrq;
+
+ // check for a completion routine of the clients to call...
+ if (pIrp->Overlay.AsynchronousParameters.UserApcRoutine)
+ {
+ (*((NBT_COMPLETION)pIrp->Overlay.AsynchronousParameters.UserApcRoutine))
+ ((PVOID)pIrp->Overlay.AsynchronousParameters.UserApcContext,
+ pIrp->IoStatus.Status,
+ pIrp->IoStatus.Information); // sent length
+
+ }
+
+ // deallocate the MDL.. this is done by the IO subsystem in IoCompleteRequest
+ IoFreeMdl(pIrp->MdlAddress);
+ REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+
+ // return this status to stop the IO subsystem from further processing the
+ // IRP - i.e. trying to complete it back to the initiating thread! -since
+ // there is no initiating thread - we are the initiator
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+
+}
+
+
+
+//----------------------------------------------------------------------------
+ PIRP
+NTAllocateNbtIrp(
+ IN PDEVICE_OBJECT DeviceObject
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates an irp by calling the IO system, and then it
+ undoes the queuing of the irp to the current thread, since these are
+ NBTs own irps, and should not be attached to a thread.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ PIRP pIrp;
+
+
+
+ // call the IO subsystem to allocate the irp
+
+ pIrp = IoAllocateIrp(DeviceObject->StackSize,FALSE);
+
+ if (!pIrp)
+ {
+ return(NULL);
+ }
+ //
+ // Simply return a pointer to the packet.
+ //
+
+ return pIrp;
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiConnect(
+ IN PTDI_REQUEST pRequestInfo,
+ IN ULONG lTimeout,
+ IN PTDI_CONNECTION_INFORMATION pSendInfo,
+ IN PIRP pClientIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a connect request to the tranport provider, to setup
+ a connection to the other side...
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ PIRP pRequestIrp;
+ PDEVICE_OBJECT pDeviceObject;
+ PFILE_OBJECT pFileObject;
+
+ // get an Irp to send the message in
+ pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
+ pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
+
+ // get an Irp from the list
+ status = GetIrp(&pRequestIrp);
+
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("Nbt:Failed to get an Irp in TdiConnect"));
+ // call the completion routine with this status
+ (*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
+ ((PVOID)pRequestInfo->RequestContext,
+ STATUS_INSUFFICIENT_RESOURCES,
+ 0L);
+ return(STATUS_PENDING);
+ }
+ pRequestIrp->CancelRoutine = NULL;
+
+ // set up the completion routine passed in from Tcp SessionStart using the APC
+ // fields in the Irp that would normally be used to complete the request
+ // back to the client - although we are really the client here so we can
+ // use these fields ourselves
+ pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
+ (PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
+ pRequestIrp->Overlay.AsynchronousParameters.UserApcContext =
+ (PVOID)pRequestInfo->RequestContext;
+
+ // store some context stuff in the Irp stack so we can call the completion
+ // routine set by the Udpsend code...
+ TdiBuildConnect(
+ pClientIrp,
+ pDeviceObject,
+ pFileObject,
+ TcpConnectComplete,
+ (PVOID)pRequestIrp, //context value passed to completion routine
+ lTimeout, // use timeout on connect
+ pSendInfo,
+ NULL);
+
+ pRequestIrp->MdlAddress = NULL;
+
+ CHECK_COMPLETION(pClientIrp);
+ status = IoCallDriver(pDeviceObject,pClientIrp);
+
+ // the transport always completes the IRP, so we always return status pending
+ return(STATUS_PENDING);
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiDisconnect(
+ IN PTDI_REQUEST pRequestInfo,
+ IN PVOID lTimeout,
+ IN ULONG Flags,
+ IN PTDI_CONNECTION_INFORMATION pSendInfo,
+ IN PCTE_IRP pClientIrp,
+ IN BOOLEAN Wait
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a connect request to the tranport provider, to setup
+ a connection to the other side...
+
+Arguments:
+
+ pClientIrp - this is the irp that the client used when it issued an
+ NbtDisconnect. We pass this irp to the transport so that
+ the client can do a Ctrl C and cancel the irp if the
+ disconnect takes too long.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ PIRP pRequestIrp;
+ PDEVICE_OBJECT pDeviceObject;
+ PFILE_OBJECT pFileObject;
+
+ // get an Irp to send the message in
+ pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
+ pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
+
+ status = GetIrp(&pRequestIrp);
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("Nbt:Failed to get an Irp in TdiDisConnect"));
+ // call the completion routine will this status
+ (*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
+ ((PVOID)pRequestInfo->RequestContext,
+ STATUS_INSUFFICIENT_RESOURCES,
+ 0L);
+ return(STATUS_PENDING);
+ }
+ if (!pClientIrp)
+ {
+ // if no client irp was passed in, then just use our Irp
+ pClientIrp = pRequestIrp;
+ }
+ pRequestIrp->CancelRoutine = NULL;
+
+ // set up the completion routine passed in from Tcp SessionStart using the APC
+ // fields in the Irp that would normally be used to complete the request
+ // back to the client - although we are really the client here so we can
+ // use these fields ourselves
+ pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
+ (PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
+ pRequestIrp->Overlay.AsynchronousParameters.UserApcContext =
+ (PVOID)pRequestInfo->RequestContext;
+
+ // store some context stuff in the Irp stack so we can call the completion
+ // routine set by the Udpsend code...
+ // Note that pRequestIrp is passed to the completion routine as a context
+ // value so we will know the routine to call for the client's completion.
+ TdiBuildDisconnect(
+ pClientIrp,
+ pDeviceObject,
+ pFileObject,
+ TcpConnectComplete,
+ (PVOID)pRequestIrp, //context value passed to completion routine
+ lTimeout,
+ Flags,
+ NULL, // send connection info
+ NULL); // return connection info
+
+ pRequestIrp->MdlAddress = NULL;
+
+ // if Wait is set, then this means do a synchronous disconnect and block
+ // until the irp is returned.
+ //
+ if (Wait)
+ {
+ status = SubmitTdiRequest(pFileObject,pClientIrp);
+ //
+ // return the irp to its pool
+ //
+ REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pRequestIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+ return(status);
+ }
+ else
+ {
+ CHECK_COMPLETION(pClientIrp);
+ status = IoCallDriver(pDeviceObject,pClientIrp);
+ // the transport always completes the IRP, so we always return status pending
+ return(STATUS_PENDING);
+ }
+
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TcpConnectComplete(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion of a TCP session setup. The TCP
+ connection is either setup or not depending on the status returned here.
+ It must called the clients completion routine (in udpsend.c). Which should
+ look after sending the NetBios sesion startup pdu across the TCP connection.
+
+ The pContext value is actually one of NBTs irps that is JUST used to store
+ the calling routines completion routine. The real Irp used is the original
+ client's irp. This is done so that IoCancelIrp will cancel the connect
+ properly.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ KIRQL OldIrq;
+ PIRP pMyIrp;
+
+ pMyIrp = (PIRP)pContext;
+
+ // check for a completion routine of the clients to call...
+ if (pMyIrp->Overlay.AsynchronousParameters.UserApcRoutine)
+ {
+ (*((NBT_COMPLETION)pMyIrp->Overlay.AsynchronousParameters.UserApcRoutine))
+ ((PVOID)pMyIrp->Overlay.AsynchronousParameters.UserApcContext,
+ pIrp->IoStatus.Status,
+ 0L);
+
+ }
+
+ REMOVE_FROM_LIST(&pMyIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pMyIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+
+ // return this status to stop the IO subsystem from further processing the
+ // IRP - i.e. trying to complete it back to the initiating thread! -since
+ // there is not initiating thread - we are the initiator
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiSend(
+ IN PTDI_REQUEST pRequestInfo,
+ IN USHORT sFlags,
+ IN ULONG SendLength,
+ OUT PULONG pSentSize,
+ IN tBUFFER *pSendBuffer,
+ IN ULONG Flags
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a packet to the transport on a TCP connection
+
+Arguments:
+
+ pSendBuffer - this is really an Mdl in NT land. It must be tacked on
+ the end of the Mdl created for the Nbt datagram header.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ PIRP pRequestIrp;
+ PMDL pMdl;
+ PDEVICE_OBJECT pDeviceObject;
+ PFILE_OBJECT pFileObject;
+
+ // get an Irp to send the message in
+ pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
+ pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
+
+ // get an Irp from the list
+ status = GetIrp(&pRequestIrp);
+
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("Nbt:Failed to get an Irp in TdiSend"));
+ // call the completion routine with this status
+ if (pRequestInfo->RequestNotifyObject)
+ {
+ (*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
+ ((PVOID)pRequestInfo->RequestContext,
+ STATUS_INSUFFICIENT_RESOURCES,
+ 0L);
+ }
+
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ pRequestIrp->CancelRoutine = NULL;
+
+
+ // set up the completion routine passed in from Udp Send using the APC
+ // fields in the Irp that would normally be used to complete the request
+ // back to the client - although we are really the client here so we can
+ // use these fields our self!
+ pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
+ (PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
+ pRequestIrp->Overlay.AsynchronousParameters.UserApcContext =
+ (PVOID)pRequestInfo->RequestContext;
+
+
+ // get the MDL that is currently linked to the IRP (i.e. created at the
+ // same time that we created the IRP list. Set the sizes correctly in
+ // the MDL header.
+ pMdl = IoAllocateMdl(
+ pSendBuffer->pDgramHdr,
+ pSendBuffer->HdrLength,
+ FALSE,
+ FALSE,
+ NULL);
+
+ if (!pMdl)
+ {
+ REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pRequestIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+
+ // call the completion routine will this status
+ if (pRequestInfo->RequestNotifyObject)
+ {
+ (*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
+ ((PVOID)pRequestInfo->RequestContext,
+ STATUS_INSUFFICIENT_RESOURCES,
+ 0L);
+ }
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // Map the pages in memory...
+ MmBuildMdlForNonPagedPool(pMdl);
+
+ TdiBuildSend(
+ pRequestIrp,
+ pDeviceObject,
+ pFileObject,
+ SendSessionCompletionRoutine,
+ NULL, //context value passed to completion routine
+ pMdl,
+ sFlags,
+ SendLength); // include session hdr length (ULONG)
+ //
+ // tack the Client's buffer on the end, if there is one
+ //
+ if (pSendBuffer->Length)
+ {
+ pMdl->Next = pSendBuffer->pBuffer;
+ }
+
+ CHECK_COMPLETION(pRequestIrp);
+ status = IoCallDriver(pDeviceObject,pRequestIrp);
+
+ *pSentSize = SendLength; // the size we attempted to send
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+SendSessionCompletionRoutine(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP pIrp,
+ IN PVOID pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion of a send to the transport.
+ It must call any client supplied completion routine and free the Irp
+ and Mdl back to its pool.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ KIRQL OldIrq;
+
+ //
+ // check for a completion routine of the clients to call...
+ //
+ if (pIrp->Overlay.AsynchronousParameters.UserApcRoutine)
+ {
+ (*((NBT_COMPLETION)pIrp->Overlay.AsynchronousParameters.UserApcRoutine))
+ ((PVOID)pIrp->Overlay.AsynchronousParameters.UserApcContext,
+ pIrp->IoStatus.Status,
+ pIrp->IoStatus.Information); // sent length
+
+ }
+
+
+
+ IoFreeMdl(pIrp->MdlAddress);
+
+ REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
+ ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
+ &pIrp->Tail.Overlay.ListEntry,
+ &NbtConfig.SpinLock);
+ //
+ // return this status to stop the IO subsystem from further processing the
+ // IRP - i.e. trying to complete it back to the initiating thread! -since
+ // there is no initiating thread - we are the initiator
+ //
+ return(STATUS_MORE_PROCESSING_REQUIRED);
+
+}
+
+
+
diff --git a/private/ntos/nbt/nt/up/makefile b/private/ntos/nbt/nt/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/nbt/nt/up/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/nbt/nt/up/netbt.prf b/private/ntos/nbt/nt/up/netbt.prf
new file mode 100644
index 000000000..84914dcb9
--- /dev/null
+++ b/private/ntos/nbt/nt/up/netbt.prf
@@ -0,0 +1,170 @@
+SendCompletion@12
+NbtDispatchInternalCtrl@8
+NTSend@8
+TdiReceiveHandler@32
+CompletionRcv@12
+ProcessIrp@24
+CTECountedAllocMem@8
+DgramHndlrNotOs@48
+ConvertToAscii@20
+UdpSendDatagram@28
+NbtDereferenceClient@4
+NTIoComplete@12
+MakeRemoteAddressStructure@16
+FindName@16
+GetIrp@4
+TdiSendDatagram@24
+DgramSendComplete@12
+FindInHashTable@16
+SendDgramCompletion@12
+CTECountedFreeMem@8
+DgramSendCleanupTracker@12
+NbtDereferenceName@4
+TdiRcvDatagramHandler@44
+GetNetBiosNameFromTransportAddress@12
+FindNameOrQuery@28
+NbtAllocTracker@0
+NbtDereferenceAddress@4
+NTSendDatagram@8
+NbtSendDatagram@28
+SendDgram@8
+ConvertToHalfAscii@16
+BuildSendDgramHdr@32
+RemoteHashTimeout@12
+TimerExpiry@16
+CTEStartTimer@16
+NTQueryInformation@8
+NTOpenConnection@8
+CreateDeviceString@8
+FreeTracker@8
+GetTracker@4
+SubmitTdiRequest@8
+TdiRcvNameSrvHandler@44
+GetEntry@12
+UdpSendNSBcast@36
+NDgramSendCompleted@12
+CreatePdu@32
+FindInEA@8
+MSnodeCompletion@12
+NbtOpenAndAssocConnection@8
+SrcIsUs@4
+AddToPendingList@8
+QueryNameOnNet@44
+NbtTdiAssociateConnection@8
+CompleteClientReq@12
+ClearCancelRoutine@4
+StartTimer@32
+StartLmHostTimer@8
+LmHostQueueRequest@16
+GetNameToFind@4
+RemoveNameAndCompleteReq@8
+RemoveName@4
+NameSrvHndlrNotOs@16
+ReturnIrp@8
+CheckRegistrationFromNet@16
+DereferenceTracker@4
+CTEInitTimer@4
+TimeoutQEntries@12
+LmHostTimeout@12
+GetContext@4
+MakePending@4
+FindNameRemoteThenLocal@8
+NbtOpenConnection@12
+NbtTdiOpenConnection@8
+NbtDispatchCreate@8
+SendDgramContinue@8
+CompletionRoutine@12
+AllocateMdl@4
+NTAssocAddress@8
+NbtAssociateAddress@12
+NTAllocateNbtIrp@4
+NbtGetMdl@8
+NbtListen@20
+NbtAllocateClientBlock@4
+NbtSetEventHandler@16
+InterlockedCallCompletion@8
+NTSetEventHandler@8
+FindInDomainList@8
+NbtRegisterName@32
+NTCheckSetCancelRoutine@12
+InitTimerQ@4
+CountLocalNames@4
+NbtInitConnQ@16
+AddToHashTable@28
+NbtInitTrackerQ@8
+NbtAppendString@12
+NbtQueryAdapterStatus@12
+QueryProviderCompletion@12
+NbtAddPermanentName@4
+ReadParameters2@8
+IncrementNameStats@8
+MSnodeRegCompletion@12
+NbtRegisterCompletion@8
+NbtOpenAddress@24
+InitQ@12
+NTSetFileObjectContexts@12
+NbtCreateDeviceObject@24
+CreateHashTable@12
+InitNotOs@0
+InitTimersNotOs@0
+TcpSendSessionResponse@12
+TcpSendSession@12
+Inbound@32
+CompleteSessionSetup@20
+SessionRespDone@12
+UdpSendResponse@32
+QueryRespDone@12
+SrcIsNameServer@8
+QueryFromNet@20
+NbtDispatchCleanup@8
+ConvertDottedDecimalToUlong@8
+NTGetLmHostPath@4
+NbtDispatchClose@8
+NbtDispatchDevCtrl@8
+NTOpenControl@8
+NbtCreateAddressObjects@12
+NTSetSharedAccess@12
+FindSessionEndPoint@24
+DispatchIoctls@12
+ReadParameters@8
+NTListen@8
+ConvertToUlong@8
+NbtInitMdlQ@8
+GetExtendedAttributes@4
+ReadNameServerAddresses@16
+GetServerAddress@12
+NbtReadRegistry@24
+GetIPFromRegistry@16
+NbtReadLinkageInformation@16
+NTReadIniString@12
+ReadElement@12
+NbtReadSingleParameter@16
+NbtOpenRegistry@12
+NbtFindLastSlash@12
+ReadStringRelative@16
+OpenAndReadElement@12
+SetEventHandler@20
+NbtTdiOpenAddress@28
+NbtTdiOpenControl@4
+SetWinsDownFlag@4
+LmGetFullPath@8
+TdiConnectHandler@36
+NTOpenAddr@8
+AcceptCompletionRoutine@12
+NTCheckSharedAccess@12
+LmOpenFile@4
+LmpBreakRecursion@8
+SendSessionCompletionRoutine@12
+ScanLmHostFile@4
+TdiSend@24
+NTReceive@8
+ClientTookSomeOfTheData@20
+LmGetIpAddr@16
+ConnectHndlrNotOs@24
+NTProcessAcceptIrp@8
+InitRemoteHashTable@12
+DriverEntry@8
+ReadLmHostFile@8
+ReadScope@8
+ClearConnStructures@8
+NbtQueryConnectionList@12
diff --git a/private/ntos/nbt/nt/up/sources b/private/ntos/nbt/nt/up/sources
new file mode 100644
index 000000000..944b046e1
--- /dev/null
+++ b/private/ntos/nbt/nt/up/sources
@@ -0,0 +1,30 @@
+!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:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+TARGETLIBS=..\..\nbt\up\obj\*\nbt.lib
+
+!include ..\sources.inc
diff --git a/private/ntos/nbt/nt/winsif.c b/private/ntos/nbt/nt/winsif.c
new file mode 100644
index 000000000..d17ab2d7e
--- /dev/null
+++ b/private/ntos/nbt/nt/winsif.c
@@ -0,0 +1,1390 @@
+/*++
+
+Copyright (c) 1989-1994 Microsoft Corporation
+
+Module Name:
+
+ Winsif.c
+
+Abstract:
+
+ This module implements all the code surrounding the WINS interface to
+ netbt that allows WINS to share the same 137 socket as netbt.
+
+Author:
+
+ Jim Stewart (Jimst) 1-30-94
+
+Revision History:
+
+--*/
+
+
+#include "nbtprocs.h"
+#include <nbtioctl.h>
+
+VOID
+WinsIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+VOID
+WinsSendIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ );
+VOID
+WinsDgramCompletion(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN NTSTATUS status,
+ IN ULONG Length
+ );
+
+NTSTATUS
+CheckIfLocalNameActive(
+ IN tREM_ADDRESS *pSendAddr
+ );
+
+PVOID
+WinsAllocMem(
+ IN ULONG Size,
+ IN BOOLEAN Rcv
+ );
+
+VOID
+WinsFreeMem(
+ IN PVOID pBuffer,
+ IN ULONG Size,
+ IN BOOLEAN Rcv
+ );
+
+VOID
+InitiateRefresh (
+ IN tDEVICECONTEXT *pDeviceContext
+ );
+
+BOOLEAN RefreshedYet;
+
+//
+// take this define from Winsock.h since including winsock.h causes
+// redefinition problems with various types.
+//
+#define AF_UNIX 1
+#define AF_INET 2
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGENBT, NTCloseWinsAddr)
+#pragma CTEMakePageable(PAGENBT, InitiateRefresh)
+#pragma CTEMakePageable(PAGENBT, RcvIrpFromWins)
+#pragma CTEMakePageable(PAGENBT, PassNamePduToWins)
+#pragma CTEMakePageable(PAGENBT, WinsIrpCancel)
+#pragma CTEMakePageable(PAGENBT, WinsSendIrpCancel)
+#pragma CTEMakePageable(PAGENBT, WinsSendDatagram)
+#pragma CTEMakePageable(PAGENBT, CheckIfLocalNameActive)
+#pragma CTEMakePageable(PAGENBT, WinsDgramCompletion)
+#pragma CTEMakePageable(PAGENBT, WinsFreeMem)
+#pragma CTEMakePageable(PAGENBT, WinsAllocMem)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+tWINS_INFO *pWinsInfo;
+HANDLE NbtDiscardableCodeHandle={0};
+
+#define COUNT_MAX 10
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTOpenWinsAddr(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles opening the Wins Object that is used by
+ by WINS to send and receive name service datagrams on port 137.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS status;
+ tWINS_INFO *pWins;
+ CTELockHandle OldIrq;
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pIrpSp->FileObject->FsContext2 =(PVOID)NBT_WINS_TYPE;
+
+
+ //
+ // if the WINs endpoint structure is not allocated, then allocate it
+ // and initialize it.
+ //
+ status = STATUS_UNSUCCESSFUL;
+ if (!pWinsInfo)
+ {
+
+ pWins = NbtAllocMem(sizeof(tWINS_INFO),NBT_TAG('v'));
+ if (pWins)
+ {
+
+ // Page in the Wins Code, if it hasn't already been paged in.
+ //
+ if (!NbtDiscardableCodeHandle)
+ {
+ NbtDiscardableCodeHandle = MmLockPagableCodeSection( NTCloseWinsAddr );
+ }
+
+ // it could fail to lock the pages so check for that
+ //
+ if (NbtDiscardableCodeHandle)
+ {
+ CTEZeroMemory(pWins,sizeof(tWINS_INFO));
+ InitializeListHead(&pWins->RcvList);
+ InitializeListHead(&pWins->SendList);
+
+ pWins->RcvMemoryMax = NbtConfig.MaxDgramBuffering;
+ pWins->SendMemoryMax = NbtConfig.MaxDgramBuffering;
+
+ status = STATUS_SUCCESS;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pWinsInfo = pWins;
+ pWinsInfo->pDeviceContext = pDeviceContext;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ pIrpSp->FileObject->FsContext = (PVOID)pWinsInfo;
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ CTEMemFree(pWins);
+ }
+
+ RefreshedYet = FALSE;
+ }
+
+
+ }
+
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Open Wins Address Rcvd, status= %X\n",status));
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTCloseWinsAddr(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp)
+
+/*++
+Routine Description:
+
+ This Routine handles closing the Wins Object that is used by
+ by WINS to send and receive name service datagrams on port 137.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS status;
+ tWINS_INFO *pWins;
+ CTELockHandle OldIrq;
+ PLIST_ENTRY pHead;
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pIrpSp->FileObject->FsContext2 = (PVOID)NBT_CONTROL_TYPE;
+
+ //
+ // if the WINs endpoint structure is allocated, then deallocate it
+ //
+ pWins = pIrpSp->FileObject->FsContext;
+ status = STATUS_INVALID_HANDLE;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ if (pWinsInfo && (pWins == pWinsInfo))
+ {
+
+ status = STATUS_SUCCESS;
+
+ //
+ // prevent any more dgram getting queued up
+ //
+ pWinsInfo = NULL;
+
+ //
+ // free any rcv buffers that may be queued up
+ //
+ pHead = &pWins->RcvList;
+ while (!IsListEmpty(pHead))
+ {
+ PLIST_ENTRY pRcvEntry;
+ tWINSRCV_BUFFER *pRcv;
+
+ KdPrint(("***Nbt:Freeing Rcv buffered for Wins\n"));
+
+ pRcvEntry = RemoveHeadList(pHead);
+
+ pRcv = CONTAINING_RECORD(pRcvEntry,tWINSRCV_BUFFER,Linkage);
+
+ WinsFreeMem(pRcv,pRcv->DgramLength,TRUE);
+
+ }
+
+ //
+ // return any Send buffers that may be queued up
+ //
+ pHead = &pWins->SendList;
+ while (!IsListEmpty(pHead))
+ {
+ PLIST_ENTRY pRcvEntry;
+ PIRP pIrp;
+
+ KdPrint(("***Nbt:Freeing Send Wins Address!\n"));
+
+ pRcvEntry = RemoveHeadList(pHead);
+
+ pIrp = CONTAINING_RECORD(pRcvEntry,IRP,Tail.Overlay.ListEntry);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ CTEIoComplete(pIrp,STATUS_CANCELLED,0);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ }
+
+ CTEMemFree(pWins);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ //
+ // Free The Wins Code section - DONOT do this to avoid any potential
+ // time windows calling these routines.
+ //
+ // MmUnlockPagableImageSection( NbtDiscardableCodeHandle );
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Close Wins Address Rcvd\n"));
+ return(status);
+
+}
+//----------------------------------------------------------------------------
+ VOID
+InitiateRefresh (
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine tries to refresh all names with WINS on THIS node.
+
+Arguments:
+
+ pDeviceContext - not used
+ pIrp - Wins Rcv Irp
+
+Return Value:
+
+ STATUS_PENDING if the buffer is to be held on to , the normal case.
+
+Notes:
+
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ ULONG Count;
+ ULONG NumberNames;
+
+
+ //
+ // be sure all net cards have this card as the primary wins
+ // server since Wins has to answer name queries for this
+ // node.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (!(NodeType & BNODE))
+ {
+ LONG i;
+ Count = 0;
+
+ NumberNames = 0;
+
+ for (i=0 ;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ )
+ {
+
+ pHead = &NbtConfig.pLocalHashTbl->Bucket[i];
+ pEntry = pHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ NumberNames++;
+ }
+ }
+
+ while (Count < COUNT_MAX)
+ {
+ if (!NbtConfig.DoingRefreshNow)
+ {
+
+ //
+ // set this to one so that refresh begin skips trying to
+ // switch to the backup.
+ //
+ NbtConfig.sTimeoutCount = 1;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ ReRegisterLocalNames();
+
+ break;
+ }
+ else
+ {
+ LARGE_INTEGER Timout;
+ NTSTATUS Locstatus;
+
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Waiting for Refresh to finish, so names can be reregistered\n"));
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ //
+ // set a timeout that should be long enough to wait
+ // for all names to fail registration with a down
+ // wins server.
+ //
+ // 2 sec*3 retries * 8 names / 5 = 9 seconds a shot.
+ // for a total of 90 seconds max.
+ //
+ Timout.QuadPart = Int32x32To64(
+ MILLISEC_TO_100NS/(COUNT_MAX/2),
+ (NbtConfig.uRetryTimeout*NbtConfig.uNumRetries)
+ *NumberNames);
+
+ Timout.QuadPart = -(Timout.QuadPart);
+
+ //
+ // wait for a few seconds and try again.
+ //
+ Locstatus = KeDelayExecutionThread(
+ KernelMode,
+ FALSE, // Alertable
+ &Timout); // Timeout
+
+
+
+ Count++;
+ if (Count < COUNT_MAX)
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ }
+ }
+ }
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+RcvIrpFromWins (
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PCTE_IRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This function takes the rcv irp posted by WINS and decides if there are
+ any datagram queued waiting to go up to WINS. If so then the datagram
+ is copied to the WINS buffer and passed back up. Otherwise the irp is
+ held by Netbt until a datagram does come in.
+
+Arguments:
+
+ pDeviceContext - not used
+ pIrp - Wins Rcv Irp
+
+Return Value:
+
+ STATUS_PENDING if the buffer is to be held on to , the normal case.
+
+Notes:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ NTSTATUS Locstatus;
+ tREM_ADDRESS *pWinsBuffer;
+ tWINSRCV_BUFFER *pBuffer;
+ PLIST_ENTRY pEntry;
+ CTELockHandle OldIrq;
+ tWINS_INFO *pWins;
+ PIO_STACK_LOCATION pIrpSp;
+
+ status = STATUS_INVALID_HANDLE;
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pWins = pIrpSp->FileObject->FsContext;
+
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ if ((!RefreshedYet) && (pWins == pWinsInfo))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ InitiateRefresh(pDeviceContext);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ RefreshedYet = TRUE;
+ }
+
+ if (pWins == pWinsInfo)
+ {
+
+ if (!IsListEmpty(&pWinsInfo->RcvList))
+ {
+ PMDL pMdl;
+ ULONG CopyLength;
+ ULONG DgramLength;
+ ULONG BufferLength;
+
+ //
+ // There is at least one datagram waiting to be received
+ //
+ pEntry = RemoveHeadList(&pWinsInfo->RcvList);
+
+ pBuffer = CONTAINING_RECORD(pEntry,tWINSRCV_BUFFER,Linkage);
+
+ //
+ // Copy the datagram and the source address to WINS buffer and
+ // return to WINS
+ //
+ pMdl = pIrp->MdlAddress;
+ pWinsBuffer = MmGetSystemAddressForMdl(pIrp->MdlAddress);
+
+
+ BufferLength = MmGetMdlByteCount(pMdl);
+ DgramLength = pBuffer->DgramLength;
+
+ CopyLength = (DgramLength <= BufferLength) ? DgramLength : BufferLength;
+ CTEMemCopy((PVOID)pWinsBuffer,
+ (PVOID)&pBuffer->Address.Family,
+ CopyLength);
+
+ //
+ // subtract from the total amount buffered for WINS since we are
+ // passing a datagram up to WINS now.
+ //
+ pWinsInfo->RcvMemoryAllocated -= pBuffer->DgramLength;
+ CTEMemFree(pBuffer);
+
+ ASSERT(pWinsBuffer->Port);
+ ASSERT(pWinsBuffer->IpAddress);
+ //
+ // pass the irp up to WINS
+ //
+ if (CopyLength < DgramLength)
+ {
+ Locstatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ Locstatus = STATUS_SUCCESS;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Returning Wins rcv Irp immediately with queued dgram, status=%X,pIrp=%X\n"
+ ,status,pIrp));
+
+ pIrp->IoStatus.Information = CopyLength;
+ pIrp->IoStatus.Status = Locstatus;
+
+
+ IoCompleteRequest(pIrp,IO_NO_INCREMENT);
+
+ return(STATUS_SUCCESS);
+
+ }
+ else
+ {
+
+ status = NTCheckSetCancelRoutine(pIrp,WinsIrpCancel,pDeviceContext);
+
+ if (!NT_SUCCESS(status))
+ {
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ NTIoComplete(pIrp,status,0);
+ }
+ else
+ {
+ pWinsInfo->RcvIrp = pIrp;
+
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Holding onto Wins Rcv Irp, pIrp =%Xstatus=%X\n",
+ status,pIrp));
+
+ status = STATUS_PENDING;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+
+ }
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = STATUS_INVALID_HANDLE;
+ NTIoComplete(pIrp,status,0);
+ }
+
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+PassNamePduToWins (
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameSrv,
+ IN ULONG uNumBytes
+ )
+/*++
+
+Routine Description:
+
+ This function is used to allow NBT to pass name query service Pdu's to
+ WINS. Wins posts a Rcv irp to Netbt. If the Irp is here then simply
+ copy the data to the irp and return it, otherwise buffer the data up
+ to a maximum # of bytes. Beyond that limit the datagrams are discarded.
+
+ If Retstatus is not success then the pdu will also be processed by
+ nbt. This allows nbt to process packets when wins pauses and
+ its list of queued buffers is exceeded.
+
+Arguments:
+
+ pDeviceContext - card that the request can in on
+ pSrcAddress - source address
+ pNameSrv - ptr to the datagram
+ uNumBytes - length of datagram
+
+Return Value:
+
+ STATUS_PENDING if the buffer is to be held on to , the normal case.
+
+Notes:
+
+
+--*/
+
+{
+ NTSTATUS Retstatus;
+ NTSTATUS status;
+ tREM_ADDRESS *pWinsBuffer;
+ PCTE_IRP pIrp;
+ CTELockHandle OldIrq;
+ PTRANSPORT_ADDRESS pSourceAddress;
+ ULONG SrcAddress;
+ SHORT SrcPort;
+
+
+ //
+ // Get the source port and ip address, since WINS needs this information.
+ //
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
+ SrcAddress = ((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr;
+ SrcPort = ((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->sin_port;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ Retstatus = STATUS_SUCCESS;
+ if (pWinsInfo)
+ {
+ if (!pWinsInfo->RcvIrp)
+ {
+ //
+ // Queue the name query pdu if we have not exeeded our current queue
+ // length
+ //
+ if (pWinsInfo->RcvMemoryAllocated < pWinsInfo->RcvMemoryMax)
+ {
+ tWINSRCV_BUFFER *pBuffer;
+
+ pBuffer = NbtAllocMem(uNumBytes + sizeof(tWINSRCV_BUFFER)+8,NBT_TAG('v'));
+ if (pBuffer)
+ {
+ //
+ // check if it is a name reg from this node
+ //
+ if (pNameSrv->AnCount == WINS_SIGNATURE)
+ {
+ pNameSrv->AnCount = 0;
+ pBuffer->Address.Family = AF_UNIX;
+ }
+ else
+ {
+ pBuffer->Address.Family = AF_INET;
+ }
+
+ CTEMemCopy((PUCHAR)((PUCHAR)pBuffer + sizeof(tWINSRCV_BUFFER)),
+ (PVOID)pNameSrv,uNumBytes);
+
+ pBuffer->Address.Port = SrcPort;
+ pBuffer->Address.IpAddress = SrcAddress;
+ pBuffer->Address.LengthOfBuffer = uNumBytes;
+
+ ASSERT(pBuffer->Address.Port);
+ ASSERT(pBuffer->Address.IpAddress);
+
+ // total amount allocated
+ pBuffer->DgramLength = uNumBytes + sizeof(tREM_ADDRESS);
+
+
+ //
+ // Keep track of the total amount buffered so that we don't
+ // eat up all non-paged pool buffering for WINS
+ //
+ pWinsInfo->RcvMemoryAllocated += pBuffer->DgramLength;
+
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Buffering Wins Rcv - no Irp, status=%X\n"));
+ InsertTailList(&pWinsInfo->RcvList,&pBuffer->Linkage);
+
+ }
+ }
+ else
+ {
+ // this ret status will allow netbt to process the packet.
+ //
+ Retstatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ else
+ {
+ PMDL pMdl;
+ ULONG CopyLength;
+ ULONG DgramLength;
+ ULONG BufferLength;
+
+ //
+ // The recv irp is here so copy the data to its buffer and
+ // pass it up to WINS
+ //
+ pIrp = pWinsInfo->RcvIrp;
+ pWinsInfo->RcvIrp = NULL;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // Copy the datagram and the source address to WINS buffer and
+ // return to WINS
+ //
+ pMdl = pIrp->MdlAddress;
+ pWinsBuffer = MmGetSystemAddressForMdl(pIrp->MdlAddress);
+
+ BufferLength = MmGetMdlByteCount(pMdl);
+ DgramLength = uNumBytes;
+
+ CopyLength = (DgramLength+sizeof(tREM_ADDRESS)) <= BufferLength ? DgramLength : BufferLength;
+
+ //
+ // check if it is a name reg from this node
+ //
+ if (pNameSrv->AnCount == WINS_SIGNATURE)
+ {
+ pNameSrv->AnCount = 0;
+ pWinsBuffer->Family = AF_UNIX;
+ }
+ else
+ {
+ pWinsBuffer->Family = AF_INET;
+ }
+ CTEMemCopy((PVOID)((PUCHAR)pWinsBuffer + sizeof(tREM_ADDRESS)),
+ (PVOID)pNameSrv,
+ CopyLength);
+
+ pWinsBuffer->Port = SrcPort;
+ pWinsBuffer->IpAddress = SrcAddress;
+ pWinsBuffer->LengthOfBuffer = uNumBytes;
+
+ ASSERT(pWinsBuffer->Port);
+ ASSERT(pWinsBuffer->IpAddress);
+
+ //
+ // pass the irp up to WINS
+ //
+ if (CopyLength < DgramLength)
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ status = STATUS_SUCCESS;
+ }
+
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Returning Wins Rcv Irp - data from net, Length=%X,pIrp=%X\n"
+ ,uNumBytes,pIrp));
+
+ NTIoComplete(pIrp,status,CopyLength);
+
+ }
+ }
+ else
+ {
+ //
+ // this ret status will allow netbt to process the packet.
+ //
+ Retstatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ return(Retstatus);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+WinsIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a WinsRcv Irp. It must release the
+ cancel spin lock before returning re: IoCancelIrp().
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ KIRQL OldIrq;
+ PIO_STACK_LOCATION pIrpSp;
+ tWINS_INFO *pWins;
+
+
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Got a Wins Irp Cancel !!! *****************\n"));
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ pWins = (tWINS_INFO *)pIrpSp->FileObject->FsContext;
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // Be sure that PassNamePduToWins has not taken the RcvIrp for a
+ // Rcv just now.
+ //
+ if ((pWins == pWinsInfo) && (pWinsInfo->RcvIrp == pIrp))
+ {
+
+ pWinsInfo->RcvIrp = NULL;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ }
+
+
+}
+//----------------------------------------------------------------------------
+ VOID
+WinsSendIrpCancel(
+ IN PDEVICE_OBJECT DeviceContext,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the cancelling a WinsRcv Irp. It must release the
+ cancel spin lock before returning re: IoCancelIrp().
+
+Arguments:
+
+
+Return Value:
+
+ The final status from the operation.
+
+--*/
+{
+ KIRQL OldIrq;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PIO_STACK_LOCATION pIrpSp;
+ tWINS_INFO *pWins;
+ BOOLEAN Found;
+ PIRP pIrpList;
+
+
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Got a Wins Send Irp Cancel !!! *****************\n"));
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ pWins = (tWINS_INFO *)pIrpSp->FileObject->FsContext;
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ if (pWins == pWinsInfo)
+ {
+ //
+ // find the matching irp on the list and remove it
+ //
+ pHead = &pWinsInfo->SendList;
+ pEntry = pHead;
+ Found = FALSE;
+
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pIrpList = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
+ if (pIrp == pIrpList)
+ {
+ RemoveEntryList(pEntry);
+ Found = TRUE;
+ }
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ if (Found)
+ {
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+ }
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ }
+
+
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+WinsSendDatagram(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PIRP pIrp,
+ IN BOOLEAN MustSend)
+
+/*++
+Routine Description:
+
+ This Routine handles sending a datagram down to the transport. MustSend
+ it set true by the Send Completion routine when it attempts to send
+ one of the queued datagrams, in case we still don't pass the memory
+ allocated check and refuse to do the send - sends will just stop then without
+ this boolean.
+
+Arguments:
+
+ pIrp - a ptr to an IRP
+
+Return Value:
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ PIO_STACK_LOCATION pIrpSp;
+ NTSTATUS status;
+ tWINS_INFO *pWins;
+ tREM_ADDRESS *pSendAddr;
+ PVOID pDgram;
+ ULONG DgramLength;
+ tDGRAM_SEND_TRACKING *pTracker;
+ CTELockHandle OldIrq;
+
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+
+ pWins = (tWINS_INFO *)pIrpSp->FileObject->FsContext;
+
+
+ status = STATUS_UNSUCCESSFUL;
+
+ //
+ // check if it is a name that is registered on this machine
+ //
+ pSendAddr = (tREM_ADDRESS *)MmGetSystemAddressForMdl(pIrp->MdlAddress);
+ if (pSendAddr->Family == AF_UNIX)
+ {
+ status = CheckIfLocalNameActive(pSendAddr);
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (pWins == pWinsInfo)
+ {
+
+ if ((pWins->SendMemoryAllocated < pWins->SendMemoryMax) || MustSend)
+ {
+
+ if (pSendAddr->IpAddress != 0)
+ {
+
+ DgramLength = pSendAddr->LengthOfBuffer;
+ pDgram = WinsAllocMem(DgramLength,FALSE);
+
+
+ if (pDgram)
+ {
+ CTEMemCopy(pDgram,
+ (PVOID)((PUCHAR)pSendAddr+sizeof(tREM_ADDRESS)),
+ DgramLength
+ );
+
+ //
+ // get a buffer for tracking Dgram Sends
+ //
+ pTracker = NbtAllocTracker();
+ if (pTracker)
+ {
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ pTracker->SendBuffer.pBuffer = NULL;
+ pTracker->SendBuffer.Length = 0;
+ pTracker->SendBuffer.pDgramHdr = pDgram;
+ pTracker->SendBuffer.HdrLength = DgramLength;
+ pTracker->pClientEle = NULL;
+ pTracker->pDestName = NULL;
+ pTracker->AllocatedLength = DgramLength;
+
+
+ // send the Datagram...
+ status = UdpSendDatagram(
+ pTracker,
+ ntohl(pSendAddr->IpAddress),
+ pDeviceContext->pNameServerFileObject,
+ WinsDgramCompletion,
+ pTracker, // context for completion
+ (USHORT)ntohs(pSendAddr->Port),
+ NBT_NAME_SERVICE);
+
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Doing Wins Send, status=%X\n",status));
+
+ // sending the datagram could return status pending,
+ // but since we have buffered the dgram, return status
+ // success to the client
+ //
+ status = STATUS_SUCCESS;
+ //
+ // Fill in the sent size
+ //
+ pIrp->IoStatus.Information = DgramLength;
+
+ }
+ else
+ {
+ WinsFreeMem((PVOID)pDgram,DgramLength,FALSE);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = STATUS_INVALID_PARAMETER;
+ }
+
+ pIrp->IoStatus.Status = status;
+ IoCompleteRequest(pIrp,IO_NO_INCREMENT);
+ }
+ else
+ {
+
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Holding onto Buffering Wins Send, status=%X\n"));
+
+
+ //
+ // Hold onto the datagram till memory frees up
+ //
+ InsertTailList(&pWins->SendList,&pIrp->Tail.Overlay.ListEntry);
+
+ status = NTCheckSetCancelRoutine(pIrp,WinsSendIrpCancel,pDeviceContext);
+ if (!NT_SUCCESS(status))
+ {
+ RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ NTIoComplete(pIrp,status,0);
+
+ }
+ else
+ {
+ status = STATUS_PENDING;
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ }
+
+
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ status = STATUS_INVALID_HANDLE;
+
+ pIrp->IoStatus.Status = status;
+ IoCompleteRequest(pIrp,IO_NO_INCREMENT);
+ }
+
+ return(status);
+
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+CheckIfLocalNameActive(
+ IN tREM_ADDRESS *pSendAddr
+ )
+
+/*++
+Routine Description
+
+ This routine checks if this is a name query response and if the
+ name is still active on the local node.
+
+Arguments:
+
+ pMdl = ptr to WINS Mdl
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ NTSTATUS status;
+ tNAMEHDR UNALIGNED *pNameHdr;
+ tNAMEADDR *pResp;
+ UCHAR pName[NETBIOS_NAME_SIZE];
+ PUCHAR pScope;
+ ULONG lNameSize;
+ CTELockHandle OldIrq;
+
+ pNameHdr = (tNAMEHDR UNALIGNED *)((PUCHAR)pSendAddr + sizeof(tREM_ADDRESS));
+ //
+ // Be sure it is a name query PDU that we are checking
+ //
+ if (((pNameHdr->OpCodeFlags & NM_FLAGS_MASK) == OP_QUERY) ||
+ ((pNameHdr->OpCodeFlags & NM_FLAGS_MASK) == OP_RELEASE))
+ {
+ status = ConvertToAscii(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ pSendAddr->LengthOfBuffer,
+ pName,
+ &pScope,
+ &lNameSize);
+
+ if (NT_SUCCESS(status))
+ {
+
+ //
+ // see if the name is still active in the local hash table
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ status = FindInHashTable(NbtConfig.pLocalHashTbl,
+ pName,
+ pScope,
+ &pResp);
+
+
+ if ((pNameHdr->OpCodeFlags & NM_FLAGS_MASK) == OP_QUERY)
+ {
+ if (NT_SUCCESS(status))
+ {
+ //
+ // if not resolved then set to negative name query resp.
+ //
+ if (!(pResp->NameTypeState & STATE_RESOLVED))
+ {
+ pNameHdr->OpCodeFlags |= htons(NAME_ERROR);
+ }
+ }
+ else
+ {
+ pNameHdr->OpCodeFlags |= htons(NAME_ERROR);
+ }
+ }
+ else
+ {
+ //
+ // check if it is a release response - if so we must have
+ // received a name release request, so mark the name in
+ // conflict and return a positive release response.
+ //
+ if (pNameHdr->OpCodeFlags & OP_RESPONSE)
+ {
+ if (NT_SUCCESS(status) &&
+ (pResp->NameTypeState & STATE_RESOLVED))
+ {
+ NbtLogEvent(EVENT_NBT_NAME_RELEASE,pSendAddr->IpAddress);
+
+ pResp->NameTypeState &= ~NAME_STATE_MASK;
+ pResp->NameTypeState |= STATE_CONFLICT;
+
+ //
+ // change to successful response
+ //
+ pNameHdr->OpCodeFlags &= 0xF0FF;
+
+ }
+ }
+ }
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ }
+ //
+ // the name is not in the local table so fail the datagram send attempt
+ //
+ return(STATUS_SUCCESS);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+WinsDgramCompletion(
+ IN tDGRAM_SEND_TRACKING *pTracker,
+ IN NTSTATUS status,
+ IN ULONG Length
+ )
+
+/*++
+Routine Description
+
+ This routine cleans up after a data gram send.
+
+Arguments:
+
+ pTracker
+ status
+ Length
+
+Return Values:
+
+ VOID
+
+--*/
+
+{
+ CTELockHandle OldIrq;
+ LIST_ENTRY *pEntry;
+ PIRP pIrp;
+ BOOLEAN MustSend;
+
+ //
+ // free the buffer used for sending the data and the tracker - note
+ // that the datagram header and the send buffer are allocated as one
+ // chunk.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (pWinsInfo)
+ {
+ WinsFreeMem((PVOID)pTracker->SendBuffer.pDgramHdr,
+ pTracker->AllocatedLength,
+ FALSE);
+
+ if (!IsListEmpty(&pWinsInfo->SendList))
+ {
+ IF_DBG(NBT_DEBUG_WINS)
+ KdPrint(("Nbt:Sending another Wins Dgram that is Queued to go\n"));
+
+ pEntry = RemoveHeadList(&pWinsInfo->SendList);
+ pIrp = CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // Send this next datagram
+ //
+ status = WinsSendDatagram(pTracker->pDeviceContext,
+ pIrp,
+ MustSend = TRUE);
+
+ pIrp->IoStatus.Status = status;
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+
+ }
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ }
+ else
+ {
+ //
+ // just free the memory since WINS has closed its address handle.
+ //
+ CTEMemFree((PVOID)pTracker->SendBuffer.pDgramHdr);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ CTEFreeMem(pTracker);
+
+
+}
+
+//----------------------------------------------------------------------------
+ PVOID
+WinsAllocMem(
+ IN ULONG Size,
+ IN BOOLEAN Rcv
+ )
+
+/*++
+Routine Description:
+
+ This Routine handles allocating memory and keeping track of how
+ much has been allocated.
+
+Arguments:
+
+ Size - number of bytes to allocate
+ Rcv - boolean that indicates if it is rcv or send buffering
+
+Return Value:
+
+ ptr to the memory allocated
+
+--*/
+
+{
+ if (Rcv)
+ {
+ if (pWinsInfo->RcvMemoryAllocated > pWinsInfo->RcvMemoryMax)
+ {
+ return NULL;
+ }
+ else
+ {
+ pWinsInfo->RcvMemoryAllocated += Size;
+ return (NbtAllocMem(Size,NBT_TAG('v')));
+ }
+ }
+ else
+ {
+ if (pWinsInfo->SendMemoryAllocated > pWinsInfo->SendMemoryMax)
+ {
+ return(NULL);
+ }
+ else
+ {
+ pWinsInfo->SendMemoryAllocated += Size;
+ return(NbtAllocMem(Size,NBT_TAG('v')));
+ }
+ }
+}
+//----------------------------------------------------------------------------
+ VOID
+WinsFreeMem(
+ IN PVOID pBuffer,
+ IN ULONG Size,
+ IN BOOLEAN Rcv
+ )
+
+/*++
+Routine Description:
+
+ This Routine handles freeing memory and keeping track of how
+ much has been allocated.
+
+Arguments:
+
+ pBuffer - buffer to free
+ Size - number of bytes to allocate
+ Rcv - boolean that indicates if it is rcv or send buffering
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ if (pWinsInfo)
+ {
+ if (Rcv)
+ {
+ pWinsInfo->RcvMemoryAllocated -= Size;
+ }
+ else
+ {
+ pWinsInfo->SendMemoryAllocated -= Size;
+ }
+ }
+
+ CTEMemFree(pBuffer);
+}
diff --git a/private/ntos/nbt/rules16.mk b/private/ntos/nbt/rules16.mk
new file mode 100644
index 000000000..fdda3283c
--- /dev/null
+++ b/private/ntos/nbt/rules16.mk
@@ -0,0 +1,79 @@
+C600 = 1
+!include $(COMMON)\src\global.mk
+
+!ifndef IMPORT
+!error IMPORT must be defined in your environment
+!endif
+
+INCLUDE=$(INCLUDE);$(IMPORT)\ddk\386\include
+PATH=$(IMPORT)\ddk\386\tools;$(IMPORT)\c700a\bin;$(IMPORT)\masm610\bin;$(PATH)
+CINCLUDES=-I$(IMPORT)\C700A\H -I$(IMPORT)\sdk\include
+AINCLUDES=-I$(IMPORT)\ddk\386\include
+LIB=$(IMPORT)\C700A\LIB;$(IMPORT)\SDK\LIB
+
+
+ASM = $(IMPORT)\masm6\binr\mlx.exe
+WIN32 = $(IMPORT)\win32
+WIN32INC= $(WIN32)\ddk\inc
+NDIS3 = $(NDIS3)
+NDIS3INC = $(NDIS3)\inc
+
+#
+# Common objects get built into Common
+#
+COMDEBBIN=$(ROOTDIR)\vxd\common\debug
+COMNODEBBIN=$(ROOTDIR)\vxd\common\nodebug
+COMDEBOBJ=$(COMDEBBIN)
+COMNODEBOBJ=$(COMNODEBBIN)
+
+#
+# Chicago specific binaries/objects
+#
+CDEBBIN=$(ROOTDIR)\vxd\chicago\debug
+CNODEBBIN=$(ROOTDIR)\vxd\chicago\nodebug
+CDEBOBJ=$(CDEBBIN)
+CNODEBOBJ=$(CNODEBBIN)
+CHIVNBTOBJD=CNODEBOBJ
+CHIDVNBTOBJD=CDEBOBJ
+
+#
+# Snowball specific binaries/objects
+#
+SDEBBIN=$(ROOTDIR)\vxd\snowball\debug
+SNODEBBIN=$(ROOTDIR)\vxd\snowball\nodebug
+SDEBOBJ=$(SDEBBIN)
+SNODEBOBJ=$(SNODEBBIN)
+SNOVNBTOBJD=SNODEBOBJ
+SNODVNBTOBJD=SDEBOBJ
+
+BLT=$(ROOTDIR)\blt
+TOOLS=$(ROOTDIR)\tools
+
+INC=$(ROOTDIR)\inc
+H=$(ROOTDIR)\h
+
+BLTF1=$(BLT:\=/)
+BLTF=$(BLTF1:.=\.)
+
+INCF1=$(INC:\=/)
+INCF=$(INCF1:.=\.)
+
+HF1=$(H:\=/)
+HF=$(HF1:.=\.)
+
+NDIS3F1=$(NDIS3INC:\=/)
+NDIS3F=$(NDIS3F1:.=\.)
+
+BASEDIRF1=$(BASEDIR:\=/)
+BASEDIRF=$(BASEDIRF1:.=\.)
+
+LINK386 = $(WIN32)\ddk\bin\link386 # flat model linker
+MAPSYM386 = $(IMPORT)\wintools\bin\mapsym32 # flat model mapsym
+ADDHDR = $(WIN32)\ddk\bin\addhdr.exe # windows AddHdr utility
+SHTOINC=$(TOOLS)\h2inc.sed
+
+{$(COMMON)\h}.h{$(BLT)}.inc:
+ $(SED) -f $(SHTOINC) <$< >$(BLT)\$(@B).inc
+
+{$(H)}.h{$(BLT)}.inc:
+ $(SED) -f $(SHTOINC) <$< >$(BLT)\$(@B).inc
diff --git a/private/ntos/nbt/setenv.bat b/private/ntos/nbt/setenv.bat
new file mode 100644
index 000000000..ecf1eb322
--- /dev/null
+++ b/private/ntos/nbt/setenv.bat
@@ -0,0 +1,46 @@
+REM
+REM Set to your local copy of the import tree from \\flipper\wb\src\import
+REM
+set IMPORT=d:\nt\import
+
+REM
+REM Not needed if running from RAZZLE screen group
+REM
+set BASEDIR=d:\nt
+
+REM
+REM Set to your local copy of the common tree from \\flipper\wb\src\common
+REM
+REM Note that I've copied it under my import tree
+REM
+set COMMON=d:\nt\import\common
+
+REM
+REM This is Henry's TCP tree. Note that you must also have built in this
+REM tree (we pick up the cxport.obj directly).
+REM
+set TCP=d:\nt\tcp
+
+REM
+REM Point to the nbt project and the dhcp project, respectively
+REM
+set DHCP=d:\nt\private\net\sockets\tcpcmd\dhcp\client\vxd
+set NBT=d:\nt\private\ntos\nbt
+
+REM
+REM Points to the Snowball NDIS3 tree
+REM
+set NDIS3=d:\nt\import\ndis3
+
+REM
+REM Points to the Chicago NDIS3 tree
+REM
+set NDIS31=d:\nt\import\ndis31
+
+
+set DEFDIR=.
+set DEFDRIVE=D:
+set SLMREMOTE=\\flipper\wb\src
+set BLDHOST=DOS
+
+PATH=%IMPORT%\COMMON\BIN;%IMPORT%\c8386\BINR;%PATH%
diff --git a/private/ntos/nbt/tools/h2inc.sed b/private/ntos/nbt/tools/h2inc.sed
new file mode 100644
index 000000000..7f82d7966
--- /dev/null
+++ b/private/ntos/nbt/tools/h2inc.sed
@@ -0,0 +1,63 @@
+/^\/\*NOINC\*\//,/^\/\*INC\*\// s'^[/*]*';'
+/^union[ ]/,/^}/s/^/;/
+/^struct[ ]/,/^};/ {
+ s/^struct[ ]\(.*\)[ ]*{/\1 struc/
+ s/^};[ ]*\/\* \(.*\) \*\//\1 ends/
+ s/^[ ]*[^ /][^ ]*[ ]*(\*[ ]*\([^\[;]*\))([ ]*\([^\[;]*\))/ \1 dd ?/
+ s/^[ ]*[^ /][^ ]*[ ]*(\*[ ]*\([^\[;]*\))([ ]*\([^\[;]*\))/ \1 dd ?/
+ s/struct[ ][ ]*[^ ]*[ ]*FAR[ ]*\*[ ]*FAR[ ]*\*[ ]*\(.*\);/ \1 dd ?/
+ s/struct[ ][ ]*[^ ]*[ ]*FAR[ ]*\*[ ]*\(.*\);/ \1 dd ?/
+ s/struct[ ][ ]*[^ ]*[ ]*far[ ]*\*[ ]*far[ ]*\*[ ]*\(.*\);/ \1 dd ?/
+ s/struct[ ][ ]*[^ ]*[ ]*far[ ]*\*[ ]*\(.*\);/ \1 dd ?/
+ s/struct[ ][ ]*[^ ]*[ ]*\*[ ]*\(.*\);/ \1 dd ?/
+ s/struct[ ]*\([^ ]*\)[ ]*\([^ ]*\);/\2 db (size \1) dup (?)/
+ s/^[ ]*unsigned[ ][^ ][^ ]*[ ]*FAR[ ]*\*[ ]*\([^\[;]*\)/ \1 dd ?/
+ s/^[ ]*unsigned[ ][^ ][^ ]*[ ]*far[ ]*\*[ ]*\([^\[;]*\)/ \1 dd ?/
+ s/^[ ]*[^ /][^ ]*[ ]*_*FAR[ ]*\*[ ]*\([^\[;]*\)/ \1 dd ?/
+ s/^[ ]*[^ /][^ ]*[ ]*_*far[ ]*\*[ ]*\([^\[;]*\)/ \1 dd ?/
+ s/^[ ]*[^ /][^ ]*[ ]*\*[ ]*\([^\[;]*\)/ \1 dd ?/
+ s/unsigned[ ]*char[ ]*\([^\[;]*\)/\1 db ?/
+ s/unsigned[ ]*int[ ]*\([^\[;]*\)/ \1 dd ?/
+ s/unsigned[ ]*short[ ]*\([^\[;]*\)/\1 dw ?/
+ s/unsigned[ ]*long[ ]*\([^\[;]*\)/\1 dd ?/
+ s/IPAddr[ ]*\([^\[;]*\)/\1 dd ?/
+ s/IPMask[ ]*\([^\[;]*\)/\1 dd ?/
+ s/NDIS_STRING[ ]*\([^\[;]*\)/\1 dd 2 dup (?)/
+ s/^[ ]\(.*_t\)[ ][ ]*\([^\[;]*\)/% \2 \1 ?/
+ s/CTETimeOutRtn[ ]*\([^\[;]*\)/\1 dd ?/
+ s/CTEEventRtn[ ]*\([^\[;]*\)/\1 dd ?/
+ s/u*char[ ][ ]*\([^\[;]*\)/\1 db ?/
+ s/u*short[ ][ ]*\([^\[;]*\)/\1 dw ?/
+ s/^\([ ]*\)u*int[ ]*\([^\[;]*\)/ \1\2 dd ?/
+ s/^\([ ]*\)u*long[ ]*\([^\[;]*\)/\1\2 dd ?/
+ s/unsigned[ ]*\([^\[;]*\)/\1 dw ?/
+ s/?\[\(.*\)\];/\1 dup (?)/
+ s/\[\(.*\)\] db (size/ db (\1*size/
+ s/\[\(.*\)\] \(d[bwd]\) ?/ \2 \1 dup (?)/
+ s/\[\(.*\)\] \(\$[PIF]\) ?/ \2 \1 dup (?)/
+ s/?;/?/
+}
+/^#define/ {
+s/sizeof *(struct *\([^)]*\))/size \1/g
+s/sizeof /size /
+s/^#define[ ]*\([^ ]*[ ]*\)[ ]0x\([0123456789abcdefABCDEF]*\)/\1 equ 0\2h/
+s/^#define[ ][ ]*\([^ ]*\)[ ][ ]*\([^ ]*\)/\1 equ \2/
+s/>>/SHR/g
+s/|/OR/g
+}
+
+/^#include/s/^#include *"\([^ ]*\)\.h"$/include \1\.inc/
+/^\([ ]*\)[\/ ]\*\/*/s//\1;/
+/\/\/\(.*\)/s//;\1/
+/\/\* \(.*\)/s//; \1/
+/ *\*\/ *$/s///
+/volatile/s/volatile//
+/^typedef/s/^/;/
+/^#if/s/#//
+/^#else/s/#//
+/^#endif/s/#//
+/^extern API_FUNCTION/,/)[ ]*;[ ]*$/s/^/;/
+/extern[ ]/s/^/;/
+/int _cdecl/,/);$/s/^/;/
+/void _cdecl/,/);$/s/^/;/
+/^API_FUNCTION/,/);$/s/^/;/
diff --git a/private/ntos/nbt/vxd.000/makefile b/private/ntos/nbt/vxd.000/makefile
new file mode 100644
index 000000000..47ff1b557
--- /dev/null
+++ b/private/ntos/nbt/vxd.000/makefile
@@ -0,0 +1,37 @@
+#############################################################################
+#
+# Microsoft Confidential
+# Copyright (C) Microsoft Corporation 1995
+# All Rights Reserved.
+#
+# Makefile for VNBT directory
+#
+#############################################################################
+ROOT = $(BLDROOT)
+DEVICEDIR = NBT
+IS_32 = TRUE
+IS_PRIVATE = TRUE
+IS_SDK = TRUE
+IS_DDK = TRUE
+DIRLIST =
+COMMONMKFILE = VNBT.mk
+LIBS=vxdwraps.lib
+
+!include $(ROOT)\DEV\MASTER.MK
+
+disk:
+ copy debug\vnbt.vxd a:vnbt.VXD
+ copy debug\vnbt.sym a:
+
+#############################################################################
+#
+# Beginning of saved settings used by makemake. Do not edit between here
+# and the end of the file, except by deleting the entire section. Do not
+# delete the blank line that precedes this comment block.
+#
+# MAKE SURE TO DELETE EVERYTHING FROM HERE TO THE END OF THE MAKEFILE BEFORE
+# YOU CHECK IT IN. If you need to add more gunk, add it BEFORE this comment
+# block.
+#
+#
+#############################################################################
diff --git a/private/ntos/nbt/vxd.000/makeres.bat b/private/ntos/nbt/vxd.000/makeres.bat
new file mode 100644
index 000000000..8808af56c
--- /dev/null
+++ b/private/ntos/nbt/vxd.000/makeres.bat
@@ -0,0 +1,5 @@
+md debug
+md retail
+set INCLUDE=%BLDROOT%\dev\ddk\inc;%BLDROOT%\net\user\common\h
+%BLDROOT%\dev\sdk\bin\RC.exe -r -DDEBUG -fodebug\VNBT.res -i %BLDROOT%\dev\sdk\inc16 ..\vxd\vnbt.rcv
+%BLDROOT%\dev\sdk\bin\RC.exe -r -foretail\VNBT.res -i %BLDROOT%\dev\sdk\inc16 ..\vxd\vnbt.rcv
diff --git a/private/ntos/nbt/vxd.000/vnbt.mk b/private/ntos/nbt/vxd.000/vnbt.mk
new file mode 100644
index 000000000..ae531fed2
--- /dev/null
+++ b/private/ntos/nbt/vxd.000/vnbt.mk
@@ -0,0 +1,122 @@
+#############################################################################
+#
+# Microsoft Confidential
+# Copyright (C) Microsoft Corporation 1995
+# All Rights Reserved.
+#
+# Makefile for VNBT device
+#
+#############################################################################
+
+
+ROOT = $(BLDROOT)
+DHCP = $(BASEDIR)\private\net\sockets\tcpcmd\dhcp\client\vxd
+NTOS = $(BASEDIR)\private\NTOS
+
+!ifndef NBT
+NBT = ..\..
+!endif # NBT
+
+DEVICE = VNBT
+SRCDIR = $(NBT)\VXD
+ALTSRCDIR = $(NBT)\NBT
+NBTINC = $(NBT)\INC
+VXDINC = ..\INC
+
+DYNAMIC=TRUE
+IS_32 = TRUE
+IS_PRIVATE = TRUE
+IS_SDK = TRUE
+IS_DDK = TRUE
+MASM6 = TRUE
+WANT_MASM611C = TRUE
+WANT_C1032 = TRUE
+BUILD_COFF = TRUE
+DEPENDNAME = ..\depend.mk
+TARGETS = dev
+PROPBINS = $(386DIR)\VNBT.VXD $(SYMDIR)\VNBT.sym
+DEVDIR=$(ROOT)\DEV\DDK\INC
+COMMON=$(BLDROOT)\net\user\common
+PCHNAM=nbtprocs
+
+DEBUGFLAGS = -DDEBUG -DSAFE=4
+
+OBJS = aaaaaaaa.obj \
+ chic.obj \
+ chicasm.obj \
+ cinit.obj \
+ client.obj \
+ ctimer.obj \
+ cvxdfile.obj \
+ cxport.obj \
+ dns.obj \
+ fileio.obj \
+ hashtbl.obj \
+ hndlrs.obj \
+ inbound.obj \
+ init.obj \
+ name.obj \
+ namesrv.obj \
+ newdns.obj \
+ nbtinfo.obj \
+ nbtutils.obj \
+ ncb.obj \
+ parse.obj \
+ proxy.obj \
+ tdiaddr.obj \
+ tdicnct.obj \
+ tdihndlr.obj \
+ tdiout.obj \
+ timer.obj \
+ udpsend.obj \
+ util.obj \
+ vnbtd.obj \
+ vxddebug.obj \
+ vxdisol.obj
+
+AFLAGS = -c -DIS_32 -nologo -W2 -Cp -Cx -DMASM6 -DCHICAGO
+CFLAGS = -c -DVXD -Zp1 -GB -Oxs -nologo -D_X86_=1 -Di386=1 -DDEVL=1 -DPROXY_NODE -DCHICAGO
+CLEANLIST = $(SRCDIR)\cxport.asm $(PCHNAM).pch
+LOCALINCS = $(SRCDIR)\cxport.asm $(VXDINC)\nbtioctl.h \
+ $(VXDINC)\sockets\netinet\in.h $(VXDINC)\sys\snet\ip_proto.h \
+ $(BLDROOT)\dev\ddk\inc\vnbt.inc
+
+!include $(ROOT)\DEV\MASTER.MK
+
+CFLAGS = $(CFLAGS) -Yu$(PCHNAM).h -Fp$(PCHNAM).pch
+
+!IF "$(VERDIR)" == "retail"
+AFLAGS = $(AFLAGS) -DSAFE=0
+CFLAGS = $(CFLAGS) -DSAFE=0
+!ENDIF
+
+!IF "$(VERDIR)" == "debug"
+AFLAGS = $(AFLAGS) $(DEBUGFLAGS)
+CFLAGS = $(CFLAGS) $(DEBUGFLAGS)
+!ENDIF
+
+INCLUDE = $(SRCDIR)\..\CMN\H;$(SRCDIR)\.;$(COMMONHDIR);$(INCLUDE);
+
+.\aaaaaaaa.obj: $(SRCDIR)\aaaaaaaa.c
+ set CL=$(CFLAGS) -Yc$(PCHNAM).h
+ $(CL) -Fo$*.obj $(SRCDIR)\$*.c
+
+#
+# This is so we can get a full COFF build. TCP doesn't use
+# COFF .obj files yet. [ERH] 10-18-95
+#
+
+$(SRCDIR)\cxport.asm: $(TCP)\vtdi\cxport.asm $(TCP)\h\cxport.h
+ copy $(TCP)\vtdi\cxport.asm $(SRCDIR)\cxport.asm
+ touch $(SRCDIR)\cxport.asm
+
+$(VXDINC)\nbtioctl.h: $(BASEDIR)\private\inc\nbtioctl.h
+ copy $(BASEDIR)\private\inc\nbtioctl.h $(VXDINC)\nbtioctl.h
+
+$(VXDINC)\sockets\netinet\in.h: $(BASEDIR)\private\inc\sockets\netinet\in.h
+ copy $(BASEDIR)\private\inc\sockets\netinet\in.h $(VXDINC)\sockets\netinet\in.h
+
+$(VXDINC)\sys\snet\ip_proto.h: $(BASEDIR)\private\inc\sys\snet\ip_proto.h
+ copy $(BASEDIR)\private\inc\sys\snet\ip_proto.h $(VXDINC)\sys\snet\ip_proto.h
+
+INCLUDE = $(NBTINC);$(SRCDIR)\.;$(ALTSRCDIR)\.;$(COMMON)\H;$(TCP)\H;$(TCP)\INC;$(DHCP);$(NBT)\inc;$(VXDINC);$(INCLUDE)
diff --git a/private/ntos/nbt/vxd/aaaaaaaa.c b/private/ntos/nbt/vxd/aaaaaaaa.c
new file mode 100644
index 000000000..ff3201866
--- /dev/null
+++ b/private/ntos/nbt/vxd/aaaaaaaa.c
@@ -0,0 +1,2 @@
+
+#include "nbtprocs.h"
diff --git a/private/ntos/nbt/vxd/chic.c b/private/ntos/nbt/vxd/chic.c
new file mode 100644
index 000000000..af3fe87e6
--- /dev/null
+++ b/private/ntos/nbt/vxd/chic.c
@@ -0,0 +1,1787 @@
+/**********************************************************************/
+/** Microsoft Windows **/
+/** Copyright(c) Microsoft Corp., 1994 **/
+/**********************************************************************/
+
+/*
+
+ chic.c
+
+ Contains VxD code that is specific to Chicago
+
+
+ FILE HISTORY:
+ Johnl 14-Mar-1994 Created
+
+*/
+
+#include <nbtprocs.h>
+#include <tdiinfo.h>
+#include <llinfo.h>
+#include <ipinfo.h>
+#include <dhcpinfo.h>
+#include <nbtinfo.h>
+
+#ifdef CHICAGO
+
+//******************* Pageable Routine Declarations ****************
+//
+// any digit 0 to 9 and '.' are legal characters in an ipaddr
+//
+#define IS_IPADDR_CHAR( ch ) ( (ch >= '0' && ch <= '9') || (ch == '.') )
+
+#define MAX_ADAPTER_DESCRIPTION_LENGTH 128
+
+const char szXportName[] = "MSTCP";
+
+//
+// asking ndis to open,read,close for every single parameter slows down
+// bootup: don't open if it's already open
+//
+NDIS_HANDLE GlobalNdisHandle = NULL;
+
+//
+// This flag is set to TRUE when the first adapter is initialized. It
+// indicates that NBT globals (such as node type, scode ID etc) have
+// had the opportunity to be set by DHCP.
+//
+BOOL fGlobalsInitialized = FALSE;
+
+//
+// As each adapter gets added, the Lana offset is added
+//
+UCHAR iLanaOffset = 0;
+
+VOID GetMacAddr( ULONG IpAddress, UCHAR MacAddr[] );
+BOOL StopAllNameQueries( tDEVICECONTEXT *pDeviceContext );
+BOOL CancelAllDelayedEvents( tDEVICECONTEXT *pDeviceContext );
+extern tTIMERQ TimerQ;
+
+BOOL GetNdisParam( LPSTR pszKey,
+ ULONG * pVal,
+ NDIS_PARAMETER_TYPE ParameterType );
+
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, IPNotification)
+#pragma CTEMakePageable(PAGE, DestroyDeviceObject)
+#pragma CTEMakePageable(PAGE, SaveNameDnsServerAddrs)
+#pragma CTEMakePageable(PAGE, GetDnsServerAddress)
+#pragma CTEMakePageable(PAGE, GetNameServerAddress)
+#pragma CTEMakePageable(PAGE, GetMacAddr)
+#pragma CTEMakePageable(PAGE, VxdReadIniString)
+#pragma CTEMakePageable(PAGE, GetProfileInt)
+#pragma CTEMakePageable(PAGE, VxdOpenNdis)
+#pragma CTEMakePageable(PAGE, GetNdisParam)
+#pragma CTEMakePageable(PAGE, VxdCloseNdis)
+#pragma CTEMakePageable(PAGE, StopAllNameQueries)
+#pragma CTEMakePageable(PAGE, VxdUnload)
+#pragma CTEMakePageable(PAGE, ReleaseNbtConfigMem)
+#endif
+
+
+/*******************************************************************
+
+ NAME: IPNotification
+
+ SYNOPSIS: Called by the IP driver when a new Lana needs to be created
+ or destroyed for an IP address.
+
+ ENTRY: pDevNode - Plug'n'Play context
+ IpAddress - New ip address
+ IpMask - New ip mask
+ fNew - Are we creating or destroying this Lana?
+
+ NOTES: This routine is only used by Chicago
+
+ HISTORY:
+ Johnl 17-Mar-1994 Created
+
+********************************************************************/
+
+TDI_STATUS IPNotification( ULONG IpAddress,
+ ULONG IpMask,
+ PVOID pDevNode,
+ USHORT IPContext,
+ BOOL fNew )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG IpNS[COUNT_NS_ADDR];
+ ULONG IpDns[COUNT_NS_ADDR];
+ int iLana;
+ UCHAR RequestedLana;
+ int i;
+ int iEmpty;
+ UCHAR PreviousNodeType;
+ UCHAR MacAddr[6];
+
+ CTEPagedCode();
+
+ KdPrint(("IPNotification entered\r\n"));
+
+ if ( !IpAddress )
+ {
+ return TDI_SUCCESS ;
+ }
+
+ if ( fNew )
+ {
+ //
+ // parameters nodetype, scope and bcastaddr are systemwide, not per
+ // adapter: so read only once.
+ //
+ if ( !fGlobalsInitialized )
+ {
+ PreviousNodeType = NodeType;
+
+ //
+ // This will re-read the DHCPable parameters now that we have
+ // a potential DHCP source
+ //
+ VxdOpenNdis();
+ ReadParameters2( pNbtGlobConfig, NULL );
+ VxdCloseNdis();
+
+ if (PreviousNodeType & PROXY)
+ {
+ NodeType |= PROXY;
+ }
+
+
+ fGlobalsInitialized = TRUE;
+ }
+
+ //
+ // Get the name servers for this device context (ip address)
+ //
+ GetNameServerAddress( IpAddress, IpNS);
+
+ //
+ // Get the DNS servers for this device context (ip address)
+ //
+ GetDnsServerAddress( IpAddress, IpDns);
+
+ //
+ // Find a free spot in our Lana table
+ //
+
+ for ( iEmpty = 0; iEmpty < NBT_MAX_LANAS; iEmpty++)
+ {
+ if (LanaTable[iEmpty].pDeviceContext == NULL)
+ goto Found;
+ }
+
+ //
+ // Lana table is full so bail
+ //
+ CDbgPrint(DBGFLAG_ERROR,("IPNotification: LanaTable full\r\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+Found:
+
+ GetMacAddr( IpAddress, MacAddr );
+
+ status = CreateDeviceObject( pNbtGlobConfig,
+ htonl( IpAddress ),
+ htonl( IpMask ),
+ IpNS[0],
+ IpNS[1],
+ IpDns[0],
+ IpDns[1],
+ MacAddr,
+ 0 );
+ if (status != STATUS_SUCCESS)
+ {
+ CDbgPrint(DBGFLAG_ERROR,("IPNotification: CreateDeviceObject Failed\r\n"));
+ return status;
+ }
+
+ //
+ // We first try and ask for a specific Lana from vnetbios based on
+ // our Lanabase and how many other Lanas we've already added. If
+ // this fails, then we will ask for Any Lana. If the LANABASE
+ // parameter is not specified, then request Any Lana.
+ //
+
+ if ( LanaBase != VXD_ANY_LANA )
+ RequestedLana = LanaBase + iLanaOffset++ ;
+ else
+ RequestedLana = VXD_ANY_LANA;
+
+RetryRegister:
+ if ( (iLana = RegisterLana2( pDevNode, RequestedLana )) == 0xff )
+ {
+ if ( RequestedLana == VXD_ANY_LANA )
+ {
+ //
+ // We couldn't get *any* lanas so bail
+ //
+ CDbgPrint(DBGFLAG_ERROR,("IPNotification: RegisterLana2 Failed\r\n"));
+ DestroyDeviceObject( pNbtGlobConfig, htonl(IpAddress));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ //
+ // Somebody may already have this Lana so beg for another one
+ //
+ RequestedLana = VXD_ANY_LANA;
+ goto RetryRegister;
+ }
+ }
+
+ KdPrint(("IPNotification: using Lana %d\r\n", iLana ));
+ LanaTable[iEmpty].pDeviceContext =
+ (tDEVICECONTEXT*)pNbtGlobConfig->DeviceContexts.Blink ;
+ LanaTable[iEmpty].pDeviceContext->iLana = iLana;
+
+ //
+ // remove our child (redir, that is!) and reenumerate our devnode
+ // so redir knows we are there!
+ //
+ ReconfigureDevnode( pDevNode );
+ }
+ else
+ {
+ status = DestroyDeviceObject( pNbtGlobConfig,
+ htonl(IpAddress) );
+
+ }
+
+ return status;
+}
+
+/*******************************************************************
+
+ NAME: DestroyDeviceObject
+
+ SYNOPSIS: Destroys the specified device
+
+ ENTRY: pConfig - Global config structure
+ IpAddr - Destroy the adapter with this address
+
+ NOTES: This routine is only used by Chicago
+
+ HISTORY:
+ Johnl 17-Mar-1994 Created
+
+********************************************************************/
+
+NTSTATUS DestroyDeviceObject(
+ tNBTCONFIG *pConfig,
+ ULONG IpAddr
+ )
+{
+ LIST_ENTRY * pEntry;
+ LIST_ENTRY * pHead;
+ tDEVICECONTEXT * pDeviceContext;
+ tDEVICECONTEXT * pTmpDeviceContext;
+ tDEVICECONTEXT * pNextDeviceContext;
+ tCLIENTELE * pClientEle;
+ tADDRESSELE * pAddress;
+ tNAMEADDR * pNameAddr;
+ tCONNECTELE * pConnEle;
+ tLOWERCONNECTION * pLowerConn;
+ PRCV_CONTEXT prcvCont;
+ tRCVELE * pRcvEle ;
+ tTIMERQENTRY * pTimer;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+ tDGRAM_SEND_TRACKING * pTracker;
+ CTELockHandle OldIrq;
+ int i;
+
+
+ CTEPagedCode();
+
+ //
+ // Find which device is going away
+ // Also, find out a device object that is still active: we need that info
+ // to update some of the address ele's.
+ //
+ pDeviceContext = NULL;
+ pNextDeviceContext = NULL;
+
+ for ( pEntry = pConfig->DeviceContexts.Flink;
+ pEntry != &pConfig->DeviceContexts;
+ pEntry = pEntry->Flink )
+ {
+ pTmpDeviceContext = CONTAINING_RECORD( pEntry, tDEVICECONTEXT, Linkage);
+ if ( pTmpDeviceContext->IpAddress == IpAddr )
+ pDeviceContext = pTmpDeviceContext;
+ else
+ pNextDeviceContext = pTmpDeviceContext;
+ }
+
+ if (pDeviceContext == NULL)
+ return STATUS_INVALID_PARAMETER;
+
+ //
+ // don't accept anymore ncbs on this device
+ //
+ pDeviceContext->fDeviceUp = FALSE;
+
+ //
+ // Close all the connections
+ //
+ NbtNewDhcpAddress( pDeviceContext, 0, 0);
+
+ if ( --NbtConfig.AdapterCount == 1)
+ NbtConfig.MultiHomed = FALSE;
+
+ ASSERT(IsListEmpty(&pDeviceContext->LowerConnFreeHead));
+
+ //
+ // if we are destroying the last device then
+ //
+ if ( NbtConfig.AdapterCount == 0)
+ {
+ //
+ // Kill off all of the Receive any from any NCBs
+ //
+ while ( !IsListEmpty( &pDeviceContext->RcvAnyFromAnyHead ))
+ {
+ pEntry = RemoveHeadList( &pDeviceContext->RcvAnyFromAnyHead ) ;
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+ CTEIoComplete( prcvCont->pNCB, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ }
+
+ //
+ // Kill off all of the Receive any datagrams from any
+ //
+ while ( !IsListEmpty(&pDeviceContext->RcvDGAnyFromAnyHead))
+ {
+ pEntry = RemoveHeadList( &pDeviceContext->RcvDGAnyFromAnyHead ) ;
+ pRcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+ CTEIoComplete( pRcvEle->pIrp, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ CTEMemFree( pRcvEle ) ;
+ }
+ }
+
+ //
+ // if any name queries are in progress, stop them now
+ //
+ StopAllNameQueries( pDeviceContext );
+
+ CancelAllDelayedEvents( pDeviceContext );
+
+ //
+ // walk through all names and see if any is being registered on this
+ // device context: if so, stop and complete it!
+ //
+ for (i=0;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ )
+ {
+ pHead = &NbtConfig.pLocalHashTbl->Bucket[i];
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ pEntry = pEntry->Flink;
+
+ if (pNameAddr->NameTypeState & STATE_RESOLVING)
+ {
+ pTimer = pNameAddr->pTimer;
+
+ //
+ // if the name registration was started for this name on this device
+ // context, stop the timer. (Completion routine will take care of
+ // doing registration on other device contexts if applicable)
+ //
+ if (pTimer)
+ {
+ pTracker = pTimer->Context;
+ ASSERT(pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+ if (pTracker->pDeviceContext == pDeviceContext)
+ {
+ ASSERT(pTracker->pNameAddr == pNameAddr)
+
+ pNameAddr->pTimer = NULL;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ StopTimer(pTimer,&pClientCompletion,&Context);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ if (pClientCompletion)
+ {
+ (*pClientCompletion)(Context,STATUS_NETWORK_NAME_DELETED);
+ }
+
+ DbgPrint("DestroyDeviceObject: stopped name reg timer") ;
+ }
+ }
+
+ }
+ }
+ }
+
+
+ //
+ // walk through all the client ele's this device context has and clean
+ // up all the mess this clientele created!
+ //
+ for ( i = 0 ; i <= pDeviceContext->cMaxNames ; i++ )
+ {
+ pClientEle = pDeviceContext->pNameTable[i];
+
+ if ( !pClientEle )
+ continue;
+
+ VxdCleanupAddress( pDeviceContext,
+ NULL,
+ pClientEle,
+ (UCHAR)i,
+ TRUE );
+ }
+
+ //
+ // close all the TDI handles
+ //
+ CloseAddressesWithTransport(pDeviceContext);
+
+ //
+ // if a call was started, but aborted then we could have some memory here!
+ //
+ while (!IsListEmpty(&pDeviceContext->UpConnectionInUse))
+ {
+ pEntry = RemoveHeadList(&pDeviceContext->UpConnectionInUse);
+ pConnEle = CONTAINING_RECORD(pEntry,tCONNECTELE,Linkage);
+ CTEMemFree( pConnEle );
+ }
+
+ while (!IsListEmpty(&pDeviceContext->LowerConnection))
+ {
+ pEntry = RemoveHeadList(&pDeviceContext->LowerConnection);
+ pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage);
+ CTEMemFree( pLowerConn );
+ }
+
+ //
+ // Remove the device from our Lana table and Vnetbios
+ //
+ for ( i = 0; i < NBT_MAX_LANAS; i++)
+ {
+ if (LanaTable[i].pDeviceContext == pDeviceContext)
+ {
+ DeregisterLana(LanaTable[i].pDeviceContext->iLana);
+ LanaTable[i].pDeviceContext = NULL;
+ KdPrint(("DestroyDeviceObject: deregistered Lana %d\r\n",pDeviceContext->iLana));
+ break;
+ }
+ }
+
+ RemoveEntryList( &pDeviceContext->Linkage);
+
+ //
+ // Walk through the AddressHead list. If any addresses exist and they
+ // point to old device context, put the next device context. Also, update
+ // adapter mask to reflect that this device context is now gone.
+ //
+ KdPrint(("DestroyDeviceObject: setting AddrEle,NameAddr fields\r\n"));
+ pHead = pEntry = &NbtConfig.AddressHead;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pAddress = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
+ ASSERT (pAddress->Verify == NBT_VERIFY_ADDRESS);
+ if (pAddress->pDeviceContext == pDeviceContext)
+ {
+ pAddress->pDeviceContext = pNextDeviceContext;
+ }
+
+ pAddress->pNameAddr->AdapterMask &= ~pDeviceContext->AdapterNumber;
+ }
+
+ if (pDeviceContext->pNameTable)
+ CTEMemFree( pDeviceContext->pNameTable );
+
+ if (pDeviceContext->pSessionTable)
+ CTEMemFree( pDeviceContext->pSessionTable );
+
+ CTEMemFree( pDeviceContext );
+
+ return STATUS_SUCCESS;
+}
+
+
+/*******************************************************************
+
+ NAME: SaveNameDnsServerAddrs
+
+ SYNOPSIS: Get the name server and dns server addrs from the registry
+ and save it in Nbtconfig. We do this so that when a new
+ adapter comes in or lease gets renewed (particularly the
+ latter), we don't have to go read the registry becuase it
+ may not be safe to do so.
+ This routine will have to be modified if setup ever changes
+ to allow configuration of name/dns servers per lana.
+
+ ENTRY: Nothing
+
+
+ HISTORY:
+ Koti 20-Nov-1994 Created
+
+********************************************************************/
+
+VOID SaveNameDnsServerAddrs( VOID )
+{
+ UCHAR i ;
+ PUCHAR pchSrv = "NameServer$" ;
+ PUCHAR pchDnsSrv = "NameServer" ;
+ PUCHAR pchSrvNum;
+ LPTSTR pchString ;
+ PUCHAR pchCurrent, pchNext;
+ BOOL fOneMore=TRUE;
+ ULONG IpNameServers[COUNT_NS_ADDR];
+
+ CTEPagedCode();
+
+ //
+ // Get Name Server ipaddrs
+ //
+
+ pchSrvNum = pchSrv + 10 ; // to overwrite '$' with 1,2,3 etc.
+
+ for ( i = 0; i < COUNT_NS_ADDR; i++)
+ {
+ IpNameServers[i] = LOOP_BACK;;
+ *pchSrvNum = '1' + i;
+
+ // call GetNdisParam directly so that we don't query dhcp here
+ // if ( !CTEReadIniString( NULL, pchSrv, &pchString ) )
+ //
+ if ( GetNdisParam( pchSrv, (ULONG *)&pchString, NdisParameterString ) )
+ {
+ if ( ConvertDottedDecimalToUlong( pchString, &IpNameServers[i] ))
+ {
+ DbgPrint("SaveNameDnsServerAddrs: bad name srv addr\r\n") ;
+ IpNameServers[i] = LOOP_BACK;
+ }
+ CTEFreeMem( pchString ) ;
+ }
+ }
+
+ //
+ // store the name server ipaddrs (potentially 0 if not defined in registry)
+ //
+ NbtConfig.lRegistryNameServerAddress = IpNameServers[0];
+ NbtConfig.lRegistryBackupServer = IpNameServers[1];
+
+
+ //
+ // Now get Dns Server ipaddrs
+ //
+
+ //
+ // initialize all of them to worst case
+ //
+ for ( i = 0; i < COUNT_NS_ADDR; i++)
+ {
+ IpNameServers[i] = LOOP_BACK;
+ }
+
+
+ // call GetNdisParam directly so that we don't query dhcp here
+ // if ( !CTEReadIniString( NULL, pchDnsSrv, &pchString ) )
+ //
+ if ( GetNdisParam( pchDnsSrv, (ULONG *)&pchString, NdisParameterString ) )
+ {
+ //
+ // we are generating (upto) COUNT_NS_ADDR pointers each pointing to
+ // one ipaddr. The string in system.ini looks like:
+ // NameServer = 11.101.4.26,200.200.200.200,1.2.3.4,1.91.245.10
+ //
+ pchNext = pchCurrent = pchString;
+
+ if ( IS_IPADDR_CHAR(*pchCurrent) ) // make sure at least one ipaddr defnd
+ {
+ i = 0;
+ while( (i < COUNT_NS_ADDR) && fOneMore )
+ {
+ while( IS_IPADDR_CHAR(*pchNext) )
+ pchNext++;
+
+ if ( *pchNext == ',' ) // ',' is the separator between 2 addrs
+ {
+ *pchNext = '\0';
+ pchNext++;
+ }
+ else
+ {
+ fOneMore = FALSE; // reached end of line
+ }
+
+ //
+ // as long as at least the first one ipaddr gets converted properly,
+ // ignore errors in others
+ //
+ if ( ConvertDottedDecimalToUlong( pchCurrent, &IpNameServers[i] ))
+ {
+ DbgPrint("SaveNameDnsServerAddrs: bad dns srv addr\r\n") ;
+ IpNameServers[i] = LOOP_BACK;
+ }
+
+ i++;
+
+ pchCurrent = pchNext; // go, convert the next one
+ }
+ }
+
+ if( pchString != NULL )
+ {
+ CTEFreeMem( pchString ) ;
+ }
+ }
+
+ //
+ // store the dns server ipaddrs (potentially 0 if not defined in registry)
+ //
+ NbtConfig.lRegistryDnsServerAddress = IpNameServers[0];
+ NbtConfig.lRegistryDnsBackupServer = IpNameServers[1];
+
+}
+
+
+/*******************************************************************
+
+ NAME: GetDnsServerAddress
+
+ SYNOPSIS: Gets the DNS server ipaddrs from the registry.
+ Or, if DHCP is installed and the DNS server addresses aren't
+ found, we get them from DHCP
+
+ ENTRY: IpAddr - If we can get from DHCP, get form this address
+ pIpDnsServer - Receives addresses if found (otherwise 0)
+
+ NOTES: This routine is only used by Snowball
+
+ HISTORY:
+ Koti 18-Oct-1994 Created
+
+********************************************************************/
+
+void GetDnsServerAddress( ULONG IpAddr, PULONG pIpDnsServer)
+{
+
+ UCHAR i ;
+ UINT OptId;
+ TDI_STATUS tdistatus ;
+ ULONG Buff[COUNT_NS_ADDR] ;
+ ULONG Size;
+
+ CTEPagedCode();
+
+
+ for ( i = 0; i < COUNT_NS_ADDR; i++)
+ {
+ pIpDnsServer[i] = LOOP_BACK ;
+ }
+
+ pIpDnsServer[0] = NbtConfig.lRegistryDnsServerAddress;
+ pIpDnsServer[1] = NbtConfig.lRegistryDnsBackupServer;
+
+ //
+ // if it was defined in the registry, we are done
+ //
+ if ( pIpDnsServer[0] != LOOP_BACK || pIpDnsServer[1] != LOOP_BACK )
+ {
+ return;
+ }
+
+ //
+ // it was not defined in the registry: try getting them from DHCP
+ //
+ Size = sizeof( Buff ) ;
+
+ OptId = 6; // DNS Option
+
+ tdistatus = DhcpQueryOption( IpAddr,
+ OptId,
+ &Buff,
+ &Size ) ;
+
+ switch ( tdistatus )
+ {
+ case TDI_SUCCESS:
+ case TDI_BUFFER_OVERFLOW: // May be more then one our buffer will hold
+ for ( i = 0; i < COUNT_NS_ADDR; i++ )
+ {
+ if ( Size >= (sizeof(ULONG)*(i+1)))
+ pIpDnsServer[i] = htonl(Buff[i]) ;
+ }
+ break ;
+
+ case TDI_INVALID_PARAMETER: // Option not found
+ break;
+
+ default:
+ ASSERT( FALSE ) ;
+ break ;
+ }
+
+ KdPrint(("GetDnsServerAddress: Primary: %x, backup: %x\r\n",
+ pIpDnsServer[0], pIpDnsServer[1] )) ;
+
+}
+
+
+/*******************************************************************
+
+ NAME: GetNameServerAddress
+
+ SYNOPSIS: Gets the Win server for the specified Lana.
+
+ Or, if DHCP is installed and the Name server addresses aren't
+ found, we get them from DHCP
+
+ ENTRY: IpAddr - If we can get from DHCP, get form this address
+ pIpNameServer - Receives addresses if found (otherwise 0)
+
+ NOTES: This routine is only used by Snowball
+
+ HISTORY:
+ Johnl 21-Oct-1993 Created
+
+********************************************************************/
+
+void GetNameServerAddress( ULONG IpAddr,
+ PULONG pIpNameServer)
+{
+ UCHAR i ;
+ UINT OptId;
+ TDI_STATUS tdistatus ;
+ ULONG Buff[COUNT_NS_ADDR] ;
+ ULONG Size;
+
+ CTEPagedCode();
+
+
+ for ( i = 0; i < COUNT_NS_ADDR; i++)
+ {
+ pIpNameServer[i] = LOOP_BACK ;
+ }
+
+ pIpNameServer[0] = NbtConfig.lRegistryNameServerAddress;
+ pIpNameServer[1] = NbtConfig.lRegistryBackupServer;
+
+ //
+ // if it was defined in the registry, we are done
+ //
+ if ( pIpNameServer[0] != LOOP_BACK || pIpNameServer[1] != LOOP_BACK )
+ {
+ return;
+ }
+
+
+ //
+ // not defined in the registry: try to get it from dhcp
+ //
+
+ OptId = 44; // NBNS Option
+
+ Size = sizeof( Buff ) ;
+
+ tdistatus = DhcpQueryOption( IpAddr,
+ OptId,
+ &Buff,
+ &Size ) ;
+
+ switch ( tdistatus )
+ {
+ case TDI_SUCCESS:
+ case TDI_BUFFER_OVERFLOW: // May be more then one our buffer will hold
+ for ( i = 0; i < COUNT_NS_ADDR; i++ )
+ {
+ if ( Size >= (sizeof(ULONG)*(i+1)))
+ pIpNameServer[i] = htonl(Buff[i]) ;
+ }
+ break ;
+
+ case TDI_INVALID_PARAMETER: // Option not found
+ break ;
+
+ default:
+ ASSERT( FALSE ) ;
+ break ;
+ }
+
+ KdPrint(("GetNameServerAddress: Primary: %x, backup: %x\r\n",
+ pIpNameServer[0], pIpNameServer[1] )) ;
+
+}
+
+
+/*******************************************************************
+
+ NAME: GetMacAddr
+
+ SYNOPSIS: Gets the mac address for the give ipaddr
+
+ ENTRY: IpAddress - the address for which to find mac addr
+ MacAddr - the array where to store mac addr
+
+ HISTORY:
+ Koti 19-Oct-1994 Created
+
+********************************************************************/
+
+VOID GetMacAddr( ULONG IpAddress, UCHAR MacAddr[] )
+{
+
+ TDI_STATUS tdistatus ;
+ int i, j, k ;
+ uchar Context[CONTEXT_SIZE] ;
+ TDIObjectID ID ;
+ TDIEntityID EList[MAX_TDI_ENTITIES] ;
+ ULONG Size ;
+ UINT NumReturned ;
+ NDIS_BUFFER ndisbuff ;
+ IFEntry *ifeAdapterInfo[MAX_TDI_ENTITIES];
+ UINT AdptNum;
+
+ CTEPagedCode();
+
+
+ //
+ // initialize to 0, in case things don't work out
+ //
+ memset( MacAddr, 0, 6 ) ;
+
+ //
+ // The first thing to do is get the list of available entities, and make
+ // sure that there are some interface entities present.
+ //
+ ID.toi_entity.tei_entity = GENERIC_ENTITY;
+ ID.toi_entity.tei_instance = 0;
+ ID.toi_class = INFO_CLASS_GENERIC;
+ ID.toi_type = INFO_TYPE_PROVIDER;
+ ID.toi_id = ENTITY_LIST_ID;
+
+ Size = sizeof(EList);
+ InitNDISBuff( &ndisbuff, &EList, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+
+ if (tdistatus != TDI_SUCCESS)
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Querying entity list failed\r\n")) ;
+ return;
+ }
+
+ NumReturned = (uint)Size/sizeof(TDIEntityID);
+
+ AdptNum = 0;
+ //
+ // first find out info about the adapters
+ //
+ for (i = 0; i < NumReturned; i++)
+ {
+ //
+ // if this entity/instance describes an adapter
+ //
+ if ( EList[i].tei_entity == IF_ENTITY )
+ {
+ DWORD isMib;
+
+
+ ID.toi_entity.tei_entity = EList[i].tei_entity ;
+ ID.toi_entity.tei_instance = EList[i].tei_instance;
+ ID.toi_class = INFO_CLASS_GENERIC ;
+ ID.toi_type = INFO_TYPE_PROVIDER;
+ ID.toi_id = ENTITY_TYPE_ID ;
+
+ Size = sizeof( isMib );
+ InitNDISBuff( &ndisbuff, &isMib, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Getting isMib failed\r\n")) ;
+ return ;
+ }
+
+ //
+ // Does this entity support MIB
+ //
+ if (isMib != IF_MIB)
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: skipping non-MIB entity\r\n")) ;
+ continue;
+ }
+
+ //
+ // MIB requests supported - query the adapter info
+ //
+
+ Size = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1;
+
+ ifeAdapterInfo[AdptNum] = (IFEntry *)CTEAllocInitMem(Size);
+
+ if ( ifeAdapterInfo[AdptNum] == NULL )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Couldn't allocate AdapterInfo buffer\r\n")) ;
+ for ( k=0; k<AdptNum; k++ )
+ {
+ CTEFreeMem( ifeAdapterInfo[k] ) ;
+ }
+ return;
+ }
+
+ ID.toi_class = INFO_CLASS_PROTOCOL;;
+ ID.toi_id = IF_MIB_STATS_ID;
+
+ Size = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1;
+ InitNDISBuff( &ndisbuff, ifeAdapterInfo[AdptNum], Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Getting IF type failed\r\n")) ;
+ for ( k=0; k<AdptNum; k++ )
+ {
+ CTEFreeMem( ifeAdapterInfo[k] ) ;
+ }
+ return ;
+ }
+
+ AdptNum++;
+ }
+ }
+
+ //
+ // now that we know about the adapters, get the ipaddrs
+ //
+ for (i = 0; i < NumReturned; i++)
+ {
+ if ( EList[i].tei_entity == CL_NL_ENTITY )
+ {
+ IPSNMPInfo IPStats ;
+ IPAddrEntry * pIAE ;
+ ULONG NLType ;
+ ULONG IpNameServer[COUNT_NS_ADDR];
+ ULONG IpDnsServer[COUNT_NS_ADDR];
+
+ //
+ // Does this entity support IP?
+ //
+
+ ID.toi_entity.tei_entity = EList[i].tei_entity ;
+ ID.toi_entity.tei_instance = EList[i].tei_instance;
+ ID.toi_class = INFO_CLASS_GENERIC ;
+ ID.toi_type = INFO_TYPE_PROVIDER;
+ ID.toi_id = ENTITY_TYPE_ID ;
+
+ Size = sizeof( NLType );
+ InitNDISBuff( &ndisbuff, &NLType, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Getting NL type failed\r\n")) ;
+ for ( k=0; k<AdptNum; k++ )
+ {
+ CTEFreeMem( ifeAdapterInfo[k] ) ;
+ }
+ return ;
+ }
+
+ if ( NLType != CL_NL_IP )
+ continue ;
+
+ //
+ // We've got an IP driver so get it's address table
+ //
+
+ ID.toi_class = INFO_CLASS_PROTOCOL ;
+ ID.toi_id = IP_MIB_STATS_ID;
+ Size = sizeof(IPStats);
+ InitNDISBuff( &ndisbuff, &IPStats, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Getting IPStats failed\r\n")) ;
+ continue ;
+ }
+
+ if ( IPStats.ipsi_numaddr < 1 )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: No IP Addresses installed\r\n")) ;
+ continue ;
+ }
+
+ Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr ;
+ if ( !(pIAE = (IPAddrEntry*) CTEAllocInitMem( Size )) )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Couldn't allocate IP table buffer\r\n")) ;
+ continue ;
+ }
+
+ ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID ;
+ InitNDISBuff( &ndisbuff, pIAE, Size, NULL ) ;
+ memset( Context, 0, CONTEXT_SIZE ) ;
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetMacAddr: Getting IP address table failed\r\n")) ;
+ CTEFreeMem( pIAE ) ;
+ continue ;
+ }
+
+ // ASSERT( Size/sizeof(IPAddrEntry) >= IPStats.ipsi_numaddr ) ;
+
+ //
+ // We have the IP address table for this IP driver. Look for
+ // our IP address
+ //
+
+ for ( j = 0 ; j < IPStats.ipsi_numaddr ; j++ )
+ {
+ //
+ // find our ipaddress
+ //
+ if ( pIAE[j].iae_addr != IpAddress )
+ {
+ continue ;
+ }
+
+ //
+ // now find out the mac address for this ipaddr
+ //
+ for ( k=0; k<AdptNum; k++ )
+ {
+ if ( ifeAdapterInfo[k]->if_index == pIAE[j].iae_index )
+ {
+ CTEMemCopy( MacAddr, ifeAdapterInfo[k]->if_physaddr, 6 );
+ break;
+ }
+ }
+ }
+
+ if (pIAE)
+ {
+ CTEFreeMem( pIAE ) ;
+ }
+ }
+ }
+
+ for ( k=0; k<AdptNum; k++ )
+ {
+ CTEFreeMem( ifeAdapterInfo[k] ) ;
+ }
+
+}
+
+
+/*******************************************************************
+
+ NAME: VxdReadIniString
+
+ SYNOPSIS: Vxd stub for CTEReadIniString
+
+ ENTRY: pchKey - Key value to look for in the NBT section
+ ppchString - Pointer to buffer found string is returned in
+
+ EXIT: ppchString will point to an allocated buffer
+
+ RETURNS: STATUS_SUCCESS if found
+
+ NOTES: The client must free ppchString when done with it
+
+ HISTORY:
+ Johnl 30-Aug-1993 Created
+
+********************************************************************/
+
+NTSTATUS VxdReadIniString( LPSTR pchKey, LPSTR * ppchString )
+{
+ CTEPagedCode();
+
+ if ( GetNdisParam( pchKey, (ULONG *)ppchString, NdisParameterString ) )
+ {
+ return STATUS_SUCCESS ;
+ }
+ else
+ {
+ //
+ // Does DHCP have it?
+ //
+
+ if ( *ppchString = (char *) GetDhcpOption( pchKey, 0 ) )
+ {
+ return STATUS_SUCCESS ;
+ }
+ }
+
+ return STATUS_UNSUCCESSFUL ;
+}
+
+/*******************************************************************
+
+ NAME: GetProfileInt
+
+ SYNOPSIS: Gets the specified value from the registry or DHCP
+
+ ENTRY: pchKey - Key value to look for in the NBT section
+ Default - Default value if not in registry or DHCP
+ Min - Minimum value can be
+
+ RETURNS: Registry Value or Dhcp value or default value
+
+ NOTES:
+
+ HISTORY:
+ Johnl 23-Mar-1994 Created
+
+********************************************************************/
+
+ULONG GetProfileInt( PVOID p, LPSTR pchKey, ULONG Default, ULONG Min )
+{
+ ULONG Val = Default;
+
+ CTEPagedCode();
+
+ //
+ // Is the value in the registry?
+ //
+ if ( !GetNdisParam( pchKey, &Val, NdisParameterInteger ) )
+ {
+ //
+ // No, Check DHCP
+ //
+ Val = GetDhcpOption( pchKey, Default );
+ }
+
+ if ( Val < Min )
+ {
+ Val = Min;
+ }
+
+ return Val;
+}
+
+ULONG GetProfileHex( PVOID p, LPSTR pchKey, ULONG Default, ULONG Min )
+{
+ return GetProfileInt( p, pchKey, Default, Min);
+}
+
+/*******************************************************************
+
+ NAME: VxdOpenNdis
+
+ SYNOPSIS: Prepare Ndis to read entries from the registry. Ndis
+ basically opens the registry and gives a handle back
+ which we store in GlobalNdisHandle.
+
+ ENTRY: Nothing (GlobalNdisHandle is global)
+ RETURNS: TRUE if things worked well
+ FALSE if some error occured
+
+ HISTORY:
+ Koti Nov. 20, 94
+
+********************************************************************/
+
+BOOL VxdOpenNdis( VOID )
+{
+
+ NDIS_STATUS Status;
+ NDIS_STRING Name;
+
+ CTEPagedCode();
+
+
+ ASSERT( !GlobalNdisHandle );
+
+ // Open the config information.
+ Name.Length = strlen(szXportName) + 1;
+ Name.MaximumLength = Name.Length;
+ Name.Buffer = (PUCHAR)szXportName;
+
+ NdisOpenProtocolConfiguration(&Status, &GlobalNdisHandle, &Name);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ // Unable to open the configuration. Fail now.
+ GlobalNdisHandle = NULL;
+ ASSERT(0);
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+/*******************************************************************
+
+ NAME: GetNdisParam
+
+ SYNOPSIS: Gets the value from the MSTCP protocol sectio of the registry
+
+ ENTRY: pchKey - Key value to look for in the NBT section
+ pVal - Retrieved parameter
+ ParameterType - Type of parameter (string, int)
+
+ RETURNS: TRUE if the value was found, FALSE otherwise
+
+ NOTES: If the parameter is a string parameter, then this routine
+ will allocate memory which the client is responsible for
+ freeing.
+
+ HISTORY:
+ Johnl 23-Mar-1994 Created
+
+********************************************************************/
+
+BOOL GetNdisParam( LPSTR pszKey,
+ ULONG * pVal,
+ NDIS_PARAMETER_TYPE ParameterType )
+{
+ NDIS_STATUS Status;
+ NDIS_STRING Name;
+ uint i;
+ PNDIS_CONFIGURATION_PARAMETER Param;
+ BOOL fRet = FALSE;
+
+ CTEPagedCode();
+
+
+ ASSERT( GlobalNdisHandle );
+
+ Name.Length = strlen(pszKey) + 1;
+ Name.MaximumLength = Name.Length;
+ Name.Buffer = pszKey;
+ NdisReadConfiguration(&Status, &Param, GlobalNdisHandle, &Name,
+ ParameterType);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if ( ParameterType == NdisParameterString)
+ {
+ LPSTR lpstr = CTEAllocInitMem( Param->ParameterData.StringData.Length + 1 ) ;
+
+ if ( lpstr )
+ {
+ strcpy( lpstr, Param->ParameterData.StringData.Buffer );
+ *pVal = (ULONG) lpstr;
+ fRet = TRUE;
+ }
+ }
+ else
+ {
+ *pVal = Param->ParameterData.IntegerData;
+ fRet = TRUE;
+ }
+ }
+
+ return fRet ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCloseNdis
+
+ SYNOPSIS: Close the handle that we opened in VxdOpenNdis
+
+ ENTRY: Nothing (GlobalNdisHandle is global)
+
+ HISTORY:
+ Koti Nov. 20, 94
+
+********************************************************************/
+
+VOID VxdCloseNdis( VOID )
+{
+
+ CTEPagedCode();
+
+ ASSERT(GlobalNdisHandle);
+
+ if (GlobalNdisHandle != NULL)
+ {
+ NdisCloseConfiguration(GlobalNdisHandle);
+ GlobalNdisHandle = NULL;
+ }
+}
+
+
+/*******************************************************************
+
+ NAME: StopAllNameQueries
+
+ SYNOPSIS: This routine is called when the device context is going
+ away. It finds out all the name queries that are in
+ progress (started by someone on this device context) and
+ stops them.
+
+ ENTRY: pDeviceContext - the device context that is going away.
+
+ RETURNS: TRUE if at least one name query was found and stopped
+ FALSE if there wasn't any query in progress
+
+ HISTORY:
+ Koti Nov. 19, 94
+
+********************************************************************/
+
+BOOL
+StopAllNameQueries( tDEVICECONTEXT *pDeviceContext )
+{
+
+ tDGRAM_SEND_TRACKING *pTracker;
+ NBT_WORK_ITEM_CONTEXT *Context;
+ PVOID pClientCompletion;
+ PVOID pClientContext;
+ tNAMEADDR *pNameAddr;
+ tTIMERQENTRY *pTimer;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ CTELockHandle OldIrq;
+
+ CTEPagedCode();
+
+ //
+ // first check to see if any names are on the pending list: all name
+ // queries over the network will be here (WINS, broadcast, DNS)
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pHead = &NbtConfig.PendingNameQueries;
+ pEntry = pHead->Flink;
+ while (pEntry != pHead)
+ {
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+
+ pEntry = pEntry->Flink;
+
+ pTimer = pNameAddr->pTimer;
+ if (pTimer)
+ {
+ pTracker = (tDGRAM_SEND_TRACKING *)pTimer->Context;
+
+ ASSERT (pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+
+ if (pTracker->pDeviceContext == pDeviceContext)
+ {
+ StopTimer(pTimer,(COMPLETIONCLIENT *)&pClientCompletion,&Context);
+ if (pClientCompletion)
+ {
+ //
+ // Remove from the pending list
+ //
+ RemoveEntryList(&pNameAddr->Linkage);
+ InitializeListHead(&pNameAddr->Linkage);
+
+ pNameAddr->pTimer = NULL;
+ NbtDereferenceName(pNameAddr);
+
+ //
+ // complete client's ncb. If requests were queued on
+ // the same name by other clients, this will start new
+ // name queries for those clients
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ CompleteClientReq(pClientCompletion,
+ (tDGRAM_SEND_TRACKING *)Context,
+ STATUS_NETWORK_NAME_DELETED);
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ DbgPrint("StopAllNameQueries: stopped net name query") ;
+ }
+ }
+ }
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ //
+ // now check if any names are on the lmhosts queue: all name queries
+ // waiting for lmhosts (and/or hosts) parsing will be here
+ //
+
+ Context = NULL;
+ if (LmHostQueries.ResolvingNow && LmHostQueries.Context)
+ {
+ Context = (NBT_WORK_ITEM_CONTEXT *)LmHostQueries.Context;
+ pTracker = Context->pTracker;
+
+ ASSERT (pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+ if (pTracker->pDeviceContext == pDeviceContext)
+ {
+ LmHostQueries.Context = NULL;
+
+ pClientCompletion = Context->ClientCompletion;
+ pClientContext = Context->pClientContext;
+
+ // name did not resolve, so delete from table
+ RemoveName(pTracker->pNameAddr);
+
+ DereferenceTracker(pTracker);
+
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ STATUS_NETWORK_NAME_DELETED);
+ DbgPrint("StopAllNameQueries: stopped lmhosts query in progress") ;
+ }
+ }
+
+ //
+ // now walk through the queued items and cancel all the relevant ones
+ //
+ pHead = &LmHostQueries.ToResolve;
+ pEntry = pHead->Flink;
+
+ while (pEntry != pHead)
+ {
+ Context = CONTAINING_RECORD(pEntry,NBT_WORK_ITEM_CONTEXT,Item.List);
+ pEntry = pEntry->Flink;
+
+ pTracker = Context->pTracker;
+
+ ASSERT (pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+ if (pTracker->pDeviceContext == pDeviceContext)
+ {
+ RemoveEntryList(&Context->Item.List);
+
+ pClientCompletion = Context->ClientCompletion;
+ pClientContext = Context->pClientContext;
+
+ // name did not resolve, so delete from table
+ RemoveName(pTracker->pNameAddr);
+
+ DereferenceTracker(pTracker);
+
+ CompleteClientReq(pClientCompletion,
+ pClientContext,
+ STATUS_NETWORK_NAME_DELETED);
+ DbgPrint("StopAllNameQueries: cancelled lmhosts queries in queue") ;
+ }
+ }
+
+}
+
+
+/*******************************************************************
+
+ NAME: VxdUnload
+
+ SYNOPSIS: This is where we are asked to unload. We destroy all
+ the device objects and then unload ourselves if the
+ message came from vtcp.
+
+ ENTRY: pchModuleName - name of the module that is going away.
+ We take action only if vtcp is going away
+ (in which case, pchModuleName is "MSTCP")
+
+ RETURNS: STATUS_SUCCESS if things went ok
+
+ HISTORY:
+ Koti Oct 5, 94
+
+********************************************************************/
+
+NTSTATUS
+VxdUnload( LPSTR pchModuleName )
+{
+
+ LIST_ENTRY * pEntry;
+ tDEVICECONTEXT * pDeviceContext;
+ NTSTATUS status;
+
+ CTEPagedCode();
+
+ KdPrint(("VxdUnload entered\r\n"));
+
+ if ( (pchModuleName == NULL) ||
+ (strcmp(pchModuleName,szXportName) != 0) )
+ {
+ CDbgPrint(DBGFLAG_ERROR,("VxdUnload: Unload msg not from MSTCP\r\n"));
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // all devices will be destroyed by the time VxdUnload is called: this is
+ // just being paranoid
+ //
+ for ( pEntry = pNbtGlobConfig->DeviceContexts.Flink;
+ pEntry != &pNbtGlobConfig->DeviceContexts;
+ )
+ {
+ pDeviceContext = CONTAINING_RECORD( pEntry, tDEVICECONTEXT, Linkage);
+ pEntry = pEntry->Flink;
+
+ status = DestroyDeviceObject(pNbtGlobConfig, pDeviceContext->IpAddress);
+
+ if (status != STATUS_SUCCESS)
+ {
+ ASSERT(0);
+ }
+ }
+
+ //
+ // events such as name refresh etc. have been scheduled to be executed
+ // later: cancel all those
+ //
+ CancelAllDelayedEvents( NULL );
+
+ //
+ // Tell IP not to use the handler anymore
+ //
+ IPRegisterAddrChangeHandler( IPNotification, FALSE);
+
+
+ ReleaseNbtConfigMem();
+
+
+ //
+ // we don't provide any service, so don't pass our name
+ //
+ CTEUnload( (char *)NULL );
+}
+
+
+
+/*******************************************************************
+
+ NAME: ReleaseNbtConfigMem
+
+ SYNOPSIS: This is where we release all the memory that was allocated
+ at init/run time via ifs mgr.
+ We also stop the various timers.
+
+ HISTORY:
+ Koti Oct 14, 94
+
+********************************************************************/
+
+VOID ReleaseNbtConfigMem( VOID )
+{
+
+ PLIST_ENTRY pHead, pEntry;
+ tTIMERQENTRY *pTimerEntry;
+ tDGRAM_SEND_TRACKING *pTrack;
+ tADDRESSELE *pAddress;
+ tCLIENTELE *pClientEle;
+ tCONNECTELE *pConnEle;
+ tLOWERCONNECTION *pLowerConn;
+ tNAMEADDR *pNameAddr;
+ CTELockHandle OldIrq;
+ int i;
+
+
+ KdPrint(("ReleaseNbtConfigMem entered\r\n"));
+
+ CTEPagedCode();
+
+
+ //
+ // stop the timer that used to look for timed-out ncb's
+ //
+ StopTimeoutTimer();
+
+ //
+ // if any other timers are active, stop them
+ //
+ if (!IsListEmpty(&TimerQ.ActiveHead))
+ {
+ pHead = &TimerQ.ActiveHead;
+ pEntry = pHead->Flink;
+ while( pEntry != pHead )
+ {
+ pTimerEntry = CONTAINING_RECORD(pEntry,tTIMERQENTRY,Linkage);
+ pEntry = pEntry->Flink;
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ StopTimer(pTimerEntry,NULL,NULL);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+ }
+
+ //
+ // free all the timers on the free list
+ //
+ while (!IsListEmpty(&TimerQ.FreeHead))
+ {
+ pEntry = RemoveHeadList(&TimerQ.FreeHead);
+ pTimerEntry = CONTAINING_RECORD(pEntry,tTIMERQENTRY,Linkage);
+ CTEMemFree(pTimerEntry);
+ }
+
+
+ // free the various buffers
+
+ if ( pFileBuff )
+ CTEMemFree( pFileBuff );
+
+ if ( NbtConfig.pHosts )
+ CTEMemFree( NbtConfig.pHosts );
+
+ if (NbtConfig.pScope)
+ CTEMemFree( NbtConfig.pScope );
+
+ if (NbtConfig.pLmHosts)
+ CTEMemFree(NbtConfig.pLmHosts);
+
+ if (NbtConfig.pDomainName)
+ CTEMemFree(NbtConfig.pDomainName);
+
+ if (NbtConfig.pDNSDomains)
+ CTEMemFree(NbtConfig.pDNSDomains);
+
+
+ //
+ // NbtDereferenceAddress might have freed the addresses. But if
+ // ReleaseNameOnNet returned pending we wouldn't have freed the addressele
+ // yet, waiting for NameReleaseDone to be called. Well, we are about to
+ // be unloaded so free such instances now!
+ //
+ while (!IsListEmpty(&NbtConfig.AddressHead))
+ {
+ pEntry = RemoveHeadList(&NbtConfig.AddressHead);
+ pAddress = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage);
+ while (!IsListEmpty(&pAddress->ClientHead))
+ {
+ pEntry = RemoveHeadList(&pAddress->ClientHead);
+ pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
+ while (!IsListEmpty(&pClientEle->ConnectActive))
+ {
+ pEntry = RemoveHeadList(&pClientEle->ConnectActive);
+ pConnEle = CONTAINING_RECORD(pEntry,tCONNECTELE,Linkage);
+ pLowerConn = pConnEle->pLowerConnId;
+ if (pLowerConn)
+ CTEMemFree(pLowerConn);
+ CTEMemFree(pConnEle);
+ }
+ CTEMemFree(pClientEle);
+ }
+ CTEMemFree( pAddress );
+ }
+
+
+ // free the DomainList
+ while (!IsListEmpty(&DomainNames.DomainList))
+ {
+ pEntry = RemoveHeadList(&DomainNames.DomainList);
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ if (pNameAddr->pIpList)
+ CTEMemFree(pNameAddr->pIpList);
+ CTEMemFree(pNameAddr);
+ }
+
+
+ // free pLocalHashTbl
+ if (NbtConfig.pLocalHashTbl)
+ {
+ //
+ // we should have freed all the entries by now. It's possible though
+ // that we sent a name release which returned pending, so we are
+ // still hanging on to the nameaddr. If there is any such instance,
+ // free it now (when else? we are about to be unloaded now!)
+ //
+ for(i=0;i<NbtConfig.pLocalHashTbl->lNumBuckets;i++)
+ {
+ while (!IsListEmpty(&(NbtConfig.pLocalHashTbl->Bucket[i])))
+ {
+ pEntry = RemoveHeadList(&(NbtConfig.pLocalHashTbl->Bucket[i]));
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ CTEMemFree(pNameAddr);
+ }
+ }
+ CTEMemFree( NbtConfig.pLocalHashTbl );
+ }
+
+
+ // free pRemoteHashTbl
+ if (NbtConfig.pRemoteHashTbl)
+ {
+ for(i=0;i<NbtConfig.pRemoteHashTbl->lNumBuckets;i++)
+ {
+ while (!IsListEmpty(&(NbtConfig.pRemoteHashTbl->Bucket[i])))
+ {
+ pEntry = RemoveHeadList(&(NbtConfig.pRemoteHashTbl->Bucket[i]));
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ CTEMemFree(pNameAddr);
+ }
+ }
+ CTEMemFree( NbtConfig.pRemoteHashTbl );
+ }
+
+
+ // free up the DgramTrackerFreeQ
+ while (!IsListEmpty(&NbtConfig.DgramTrackerFreeQ))
+ {
+ pEntry = RemoveHeadList(&NbtConfig.DgramTrackerFreeQ);
+ pTrack = CONTAINING_RECORD(pEntry,tDGRAM_SEND_TRACKING,Linkage);
+ CTEMemFree( pTrack );
+ }
+
+ //
+ // shouldn't see any pending name queries at this point, but just in case!
+ //
+ while (!IsListEmpty(&NbtConfig.PendingNameQueries))
+ {
+ pEntry = RemoveHeadList(&NbtConfig.PendingNameQueries);
+ pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage);
+ CTEMemFree( pNameAddr );
+ }
+
+
+ // free the SessionBufferFreeList list (allocated, not used)
+ while( !IsListEmpty(&NbtConfig.SessionBufferFreeList) )
+ {
+ pEntry = RemoveHeadList(&NbtConfig.SessionBufferFreeList);
+ CTEMemFree( pEntry );
+ }
+
+
+ // free SendContextFreeList (allocated, not used)
+ while( !IsListEmpty(&NbtConfig.SendContextFreeList) )
+ {
+ pEntry = RemoveHeadList(&NbtConfig.SendContextFreeList);
+ CTEMemFree( pEntry );
+ }
+
+
+ // free RcvContextFreeList (allocated, not used)
+ while( !IsListEmpty(&NbtConfig.RcvContextFreeList) )
+ {
+ pEntry = RemoveHeadList(&NbtConfig.RcvContextFreeList);
+ CTEMemFree( pEntry );
+ }
+
+#ifdef DBG
+ if( !IsListEmpty(&DbgMemList) )
+ {
+ KdPrint(("ReleaseNbtConfigMem: memory leak!\r\n"));
+ if (DbgLeakCheck)
+ {
+ ASSERT(0);
+ }
+ }
+#endif
+
+}
+
+#endif // CHICAGO
diff --git a/private/ntos/nbt/vxd/chicasm.asm b/private/ntos/nbt/vxd/chicasm.asm
new file mode 100644
index 000000000..2536b30f7
--- /dev/null
+++ b/private/ntos/nbt/vxd/chicasm.asm
@@ -0,0 +1,122 @@
+;*****************************************************************;
+;** Copyright(c) Microsoft Corp., 1988-1993 **;
+;*****************************************************************;
+;:ts=8
+ TITLE CHICASM.ASM - Chicago (PNP) Specific vnbt routines
+.XLIST
+;*** VNBT -- NetBios over TCP/IP VxD
+;
+;
+ .386p
+ include vmm.inc
+ include dosmgr.inc
+ include netvxd.inc
+ include vdhcp.inc
+ include debug.inc
+ include vtdi.inc
+ include vip.inc
+
+ include vnbt.inc
+ include vnetbios.inc
+.LIST
+
+IFDEF CHICAGO
+
+EXTRN _GetDhcpOption:NEAR
+EXTRN NCB_Handler:NEAR
+
+
+VxD_CODE_SEG
+
+;****************************************************************************
+;** _RegisterLana2
+;
+; Registers the requested lana with the VNetbios driver.
+;
+; Entry: [ESP+4] - PNP Device context
+; [ESP+8] - Lana number to register
+;
+; Exit: EAX will return the lana registered or 0xff if the lana couldn't
+; be registered.
+;
+; Uses:
+;
+BeginProc _RegisterLana2
+
+ VxDcall VNETBIOS_Get_Version
+ jnc Do_Register
+ mov eax, 0ffh ; yukk! vnetbios is not loaded!
+ jmp Register_Fail
+
+Do_Register:
+ mov ecx, [esp+4] ; PNP device context
+ mov eax, [esp+8] ; Get the request lana to register
+
+ push ebx
+ push edx
+
+ mov ebx, 1 ; Take over RM lana
+ mov edx, NCB_Handler
+ VxDcall VNETBIOS_Register2 ; Carry set on failure
+ jnc RegLana10
+ mov eax, 0ffh ; Failed
+
+RegLana10:
+ pop edx
+ pop ebx
+Register_Fail:
+ ret
+
+EndProc _RegisterLana2
+
+
+;****************************************************************************
+;** _DeregisterLana
+;
+; Deregisters the requested lana with the VNetbios driver.
+;
+; Entry: [ESP+4] - Lana number to deregister
+;
+; Uses:
+;
+BeginProc _DeregisterLana
+
+ mov eax, [esp+4] ; Lana to deregister
+
+ VxDcall VNETBIOS_Deregister
+
+ ret
+EndProc _DeregisterLana
+
+;****************************************************************************
+;** _IPRegisterAddrChangeHandler
+;
+; Registers a handler with IP to handle binding and unbinding
+;
+; Entry: [ESP+4] - Pointer to handler
+; [ESP+8] - TRUE to set the handler, FALSE to remove the handler
+;
+; Exit: EAX will contain TRUE if successful, FALSE other wise
+;
+; Uses:
+;
+BeginProc _IPRegisterAddrChangeHandler
+
+ mov eax, [esp+8] ; bool
+ push eax
+ mov eax, [esp+8] ; Handler (yes, it should be esp+8)
+ push eax
+
+ VxDcall VIP_Register_Addr_Change; Carry set on failure
+
+ add esp, 8
+ ret
+
+EndProc _IPRegisterAddrChangeHandler
+
+VxD_CODE_ENDS
+
+ENDIF ;CHICAGO
+
+END
+
diff --git a/private/ntos/nbt/vxd/cinit.c b/private/ntos/nbt/vxd/cinit.c
new file mode 100644
index 000000000..c8e9c4efd
--- /dev/null
+++ b/private/ntos/nbt/vxd/cinit.c
@@ -0,0 +1,930 @@
+/**********************************************************************/
+/** Microsoft Windows **/
+/** Copyright(c) Microsoft Corp., 1993 **/
+/**********************************************************************/
+
+/*
+
+ Init.c
+
+ Contains VxD initialization code
+
+
+ FILE HISTORY:
+ Johnl 24-Mar-1993 Created
+
+*/
+
+#include <nbtprocs.h>
+#include <tdiinfo.h>
+#include <ipinfo.h>
+#include <dhcpinfo.h>
+#include <nbtinfo.h>
+#include <hosts.h>
+
+int Init( void ) ;
+int RegisterLana( int Lana ) ;
+
+ NTSTATUS
+NbtReadRegistry(
+ OUT tNBTCONFIG *pConfig
+ ) ;
+
+extern char DNSSectionName[]; // Section where we find DNS domain name
+
+VOID GetDNSInfo( VOID );
+
+ULONG GetDhcpOption( PUCHAR ValueName, ULONG DefaultValue );
+
+VOID ParseDomainNames(
+ PUCHAR *ppDomainName,
+ PUCHAR *ppDNSDomains
+ );
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(INIT, Init)
+#pragma CTEMakePageable(PAGE, NbtReadRegistry)
+#pragma CTEMakePageable(PAGE, GetDNSInfo)
+#pragma CTEMakePageable(PAGE, CreateDeviceObject)
+#pragma CTEMakePageable(PAGE, GetDhcpOption)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+//
+// Initialized in VNBT_Device_Init with the protocol(s) this driver sits
+// on. Note that we currently only support one. This should *not* be in
+// the initialization data segments.
+//
+TDIDispatchTable * TdiDispatch ;
+UCHAR LanaBase ;
+BOOL fInInit = TRUE ;
+
+//
+// Used in conjunction with the CHECK_INT_TABLE macro
+//
+#ifdef DEBUG
+ BYTE abVecTbl[256] ;
+ DWORD DebugFlags = DBGFLAG_ALL | DBGFLAG_KDPRINTS ;
+ char DBOut[4096] ;
+ int iCurPos = 0 ;
+
+void NbtDebugOut( char * str )
+{
+ if ( DebugFlags & (DBGFLAG_AUX_OUTPUT | DBGFLAG_ERROR) )
+ CTEPrint( str ) ;
+
+ iCurPos += strlen( str ) + 1 ;
+
+ if ( iCurPos >= sizeof(DBOut) )
+ iCurPos = 0;
+}
+
+#endif // DEBUG
+
+#pragma BEGIN_INIT
+
+//
+// While reading initialization parameters, we may need to go to
+// the DHCP driver. This communicates to the init routine which device
+// we are currently interested in.
+// 0xfffffff means get the requested option for any IP address.
+//
+// MUST BE IN NETWORK ORDER!!!
+//
+ULONG CurrentIP = 0xffffffff ;
+
+/*******************************************************************
+
+ NAME: Init
+
+ SYNOPSIS: Performs all driver initialization
+
+ RETURNS: TRUE if initialization successful, FALSE otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 24-Mar-1993 Created
+
+********************************************************************/
+
+int Init( void )
+{
+ NTSTATUS status ;
+ int i ;
+ ULONG ulTmp ;
+ int Retval;
+
+
+ Retval = FALSE;
+
+ if ( CTEInitialize() )
+ {
+ DbgPrint("Init: CTEInitialize succeeded\n\r") ;
+ }
+ else
+ goto fail_init;
+
+ INIT_NULL_PTR_CHECK() ;
+
+#ifdef DEBUG
+ InitializeListHead(&DbgMemList);
+ DbgLeakCheck = 0;
+#endif
+
+#ifdef CHICAGO
+ //
+ // Tell TDI who to call if someone underneath unloads
+ //
+ CTESetUnloadNotifyProc( (CTENotifyRtn)VxdUnload );
+
+ //
+ // prepare to read a bunch of parms from the registry
+ //
+ VxdOpenNdis();
+#endif
+
+ CTERefillMem() ;
+ CTEZeroMemory( pNbtGlobConfig, sizeof(*pNbtGlobConfig));
+
+ status = NbtReadRegistry( pNbtGlobConfig ) ;
+ if ( !NT_SUCCESS( status ) )
+ {
+ DbgPrint("Init: NbtReadRegistry failed\n\r") ;
+ goto fail_init;
+ }
+
+ InitializeListHead(&pNbtGlobConfig->DelayedEvents);
+
+ InitializeListHead(&pNbtGlobConfig->BlockingNcbs);
+
+ status = InitNotOs() ;
+ if ( !NT_SUCCESS( status ) )
+ {
+ DbgPrint("Init: InitNotOs failed\n\r") ;
+ goto fail_init;
+ }
+
+ status = InitTimersNotOs() ;
+ if ( !NT_SUCCESS( status ) )
+ {
+ DbgPrint("Init: InitTimersNotOs failed\n\r") ;
+ StopInitTimers() ;
+ goto fail_init;
+ }
+
+#ifdef CHICAGO
+
+ //
+ // if name server and/or dns server are defined in registry, read them now
+ //
+ SaveNameDnsServerAddrs();
+
+ //
+ // Register an IP notification routine when new adapters are added or
+ // DHCP brings up an address
+ //
+
+ if ( !IPRegisterAddrChangeHandler( IPNotification, TRUE))
+ {
+ DbgPrint("Init: Failed to register with IP driver\r\n") ;
+ StopInitTimers() ;
+ goto fail_init;
+ }
+#else
+ //
+ // Find all the active Lanas
+ //
+
+ if ( !GetActiveLanasFromIP() )
+ {
+ DbgPrint("Init: Failed to get addresses from IP driver\r\n") ;
+ StopInitTimers() ;
+ goto fail_init;
+ }
+
+#endif
+
+ //
+ // find out where hosts file is, what's the domain name etc.
+ //
+ GetDNSInfo();
+
+ //
+ // Get the NCB timeout timer going
+ //
+ if ( !CheckForTimedoutNCBs( NULL, NULL) )
+ {
+ DbgPrint("Init: CheckForTimedoutNCBs failed\n\r") ;
+ StopInitTimers() ;
+ goto fail_init;
+ }
+
+ fInInit = FALSE ;
+ CTERefillMem() ;
+ Retval = TRUE ;
+
+
+fail_init:
+
+#ifdef CHICAGO
+ VxdCloseNdis();
+#endif
+
+ return( Retval );
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtReadRegistry(
+ OUT tNBTCONFIG *pConfig
+ )
+/*++
+
+Routine Description:
+
+ This routine is called to get information from the registry,
+ starting at RegistryPath to get the parameters.
+
+Arguments:
+
+ pNbtConfig - ptr to global configuration strucuture for NBT
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS ;
+ int i;
+
+ CTEPagedCode();
+
+ //
+ // Initialize the Configuration data structure
+ //
+ CTEZeroMemory(pConfig,sizeof(tNBTCONFIG));
+
+ ReadParameters( pConfig, NULL );
+
+ //
+ // Allocate necessary memory for lmhosts support if a lmhosts file
+ // was specified (was read from .ini file in ReadParameters)
+ //
+ if ( pConfig->pLmHosts )
+ {
+ if ( !VxdInitLmHostsSupport( pConfig->pLmHosts,
+ 260 /*strlen(pConfig->pLmHosts)+1*/ ))
+ {
+ return STATUS_INSUFFICIENT_RESOURCES ;
+ }
+
+ pConfig->EnableLmHosts = TRUE ;
+ }
+ else
+ {
+ pConfig->EnableLmHosts = FALSE ;
+ }
+
+ // keep the size around for allocating memory, so that when we run over
+ // OSI, only this value should change (in theory at least)
+ pConfig->SizeTransportAddress = sizeof(TDI_ADDRESS_IP);
+
+ // fill in the node type value that is put into all name service Pdus
+ // that go out identifying this node type
+ switch (NodeType)
+ {
+ case BNODE:
+ pConfig->PduNodeType = 0;
+ break;
+ case PNODE:
+ pConfig->PduNodeType = 1 << 13;
+ break;
+ case MNODE:
+ pConfig->PduNodeType = 1 << 14;
+ break;
+ case MSNODE:
+ pConfig->PduNodeType = 3 << 13;
+ break;
+
+ }
+
+ LanaBase = (UCHAR) CTEReadSingleIntParameter( NULL,
+ VXD_LANABASE_NAME,
+ VXD_DEF_LANABASE,
+ 0 ) ;
+ CTEZeroMemory( LanaTable, NBT_MAX_LANAS * sizeof( LANA_ENTRY )) ;
+
+ return Status;
+}
+
+/*******************************************************************
+
+ NAME: GetDNSInfo
+
+ SYNOPSIS: Gets path to windows dir, then appends hosts to it
+
+ RETURNS: Nothing
+
+ NOTES: If something goes wrong, path is set to NULL
+
+ HISTORY:
+ Koti 13-July-1994 Created
+
+********************************************************************/
+
+VOID GetDNSInfo( VOID )
+{
+
+ PUCHAR pszWinPath;
+ PUCHAR pszHosts="hosts";
+ PUCHAR pszHostsPath=NULL;
+#ifdef CHICAGO
+ PUCHAR pszParmName="Domain";
+ PUCHAR pszParm2Name = "SearchList";
+#else
+ PUCHAR pszParmName="DomainName";
+ PUCHAR pszParm2Name = "DNSDomains";
+#endif
+ PUCHAR pszDomName;
+ PUCHAR pchTmp;
+ int len;
+
+
+ CTEPagedCode();
+
+ NbtConfig.pHosts = NULL;
+
+ //
+ // Remember, pszWinPath has '\' at the end: (i.e. Get_Config_Directory
+ // returns pointer to "c:\windows\" )
+ //
+ pszWinPath = VxdWindowsPath();
+
+ //
+ // doc implies Get_Config_Directory can't fail! But we are paranoid...
+ //
+
+ if (pszWinPath == NULL)
+ {
+ pszHostsPath = NULL;
+ return;
+ }
+
+ len = strlen(pszWinPath) + strlen(pszHosts) + 1;
+
+ //
+ // allocate memory to hold "c:\windows\hosts" or whatever
+ //
+ pszHostsPath = CTEAllocInitMem( len );
+ if (pszHostsPath == NULL)
+ return;
+
+ strcpy(pszHostsPath, pszWinPath);
+ strcat(pszHostsPath, pszHosts);
+
+ NbtConfig.pHosts = pszHostsPath;
+
+ NbtConfig.pDomainName = NULL;
+//
+// chicago gets the string from the registry, snowball from system.ini
+//
+ NbtConfig.pDNSDomains = NULL;
+
+#ifdef CHICAGO
+ if ( !CTEReadIniString( NULL, pszParmName, &pchTmp ) )
+ {
+ NbtConfig.pDomainName = pchTmp;
+ }
+
+ if ( !CTEReadIniString( NULL, pszParm2Name, &pchTmp ) )
+ {
+ if (pchTmp[0] != '\0')
+ {
+ NbtConfig.pDNSDomains = pchTmp;
+ }
+ else
+ {
+ CTEMemFree(pchTmp);
+ }
+ }
+#else
+ pchTmp = GetProfileString( pszParmName, NULL, DNSSectionName );
+ if ( pchTmp != NULL )
+ {
+ if ( pszDomName = CTEAllocInitMem( strlen( pchTmp ) + 1 ) )
+ {
+ strcpy( pszDomName, pchTmp ) ;
+
+ NbtConfig.pDomainName = pszDomName;
+ }
+ }
+
+ pchTmp = GetProfileString( pszParm2Name, NULL, DNSSectionName );
+ if ( pchTmp != NULL && pchTmp[0] != '\0')
+ {
+ if ( pszDomName = CTEAllocInitMem( strlen( pchTmp ) + 1) )
+ {
+ strcpy( pszDomName, pchTmp ) ;
+
+ NbtConfig.pDNSDomains = pszDomName;
+ }
+ }
+#endif
+
+ ParseDomainNames( &NbtConfig.pDomainName, &NbtConfig.pDNSDomains);
+
+ return;
+}
+
+/*******************************************************************
+
+ NAME: ParseDomainNames
+
+ SYNOPSIS: Extracts heirarchical domain names from the primary DNS
+ domain name, and prepends any found to the domains list.
+
+ ENTRY: ppDomainName - pointer to pointer to primary DNS domain name
+ ppDNSDomains - pointer to pointer to other DNS domain names
+
+ EXIT: *ppDNSDomains updated with pointer to new DNS domains list
+ if any other heirarchical levels found in *ppDomainName.
+
+ RETURNS: nothing
+
+ NOTES:
+
+ HISTORY:
+ EarleH 10-Jan-1996 Created
+
+********************************************************************/
+
+VOID ParseDomainNames(
+ PUCHAR *ppDomainName,
+ PUCHAR *ppDNSDomains
+ )
+{
+ PUCHAR pStr;
+ UINT iCount;
+ PUCHAR pDomainName = *ppDomainName, pDNSDomains = *ppDNSDomains, pNewDNSDomains;
+
+ if ( pDomainName != NULL )
+ {
+ for ( iCount = 0, pStr = pDomainName ; pStr[0] != '\0' ; pStr++ )
+ {
+ if ( pStr[0] == '.' )
+ {
+ iCount += strlen ( pStr );
+ }
+ }
+ if ( pDNSDomains != NULL )
+ {
+ iCount += strlen ( pDNSDomains );
+ if ( iCount )
+ {
+ iCount++; // for the separator
+ }
+ }
+ if (iCount++) // ++ for the terminator
+ {
+ pNewDNSDomains = CTEAllocInitMem( iCount );
+ if ( pNewDNSDomains != NULL )
+ {
+ pNewDNSDomains[0] = '\0';
+ for ( pStr = pDomainName ; pStr[0] != '\0' ; pStr++ )
+ {
+ if ( pStr[0] == '.' )
+ {
+ pStr++;
+ if ( pNewDNSDomains[0] != '\0' )
+ {
+ strcat ( pNewDNSDomains, "," );
+ }
+ strcat ( pNewDNSDomains, pStr );
+ }
+ }
+ if ( pDNSDomains != NULL )
+ {
+ strcat ( pNewDNSDomains, "," );
+ strcat ( pNewDNSDomains, pDNSDomains );
+ CTEMemFree( pDNSDomains );
+ }
+ if ( pNewDNSDomains[0] != '\0' )
+ {
+ *ppDNSDomains = pNewDNSDomains;
+ }
+ else
+ {
+ *ppDNSDomains = NULL;
+ }
+ }
+ }
+ }
+}
+
+#pragma END_INIT
+
+#ifndef CHICAGO
+#pragma BEGIN_INIT
+#endif
+/*******************************************************************
+
+ NAME: CreateDeviceObject
+
+ SYNOPSIS: Initializes the device list of the global configuration
+ structure
+
+ ENTRY: pConfig - Pointer to global config structure
+ IpAddr - IP Address for this adapter
+ IpMask - IP Mask for this adapter
+ IpNameServer - IP Address of the name server for this adapter
+ IpBackupServer - IP Address of the backup name server for
+ this adapter
+ IpDnsServer - IP Address of the dns server for this adapter
+ IpDnsBackupServer - IP Address of the backup dns server
+ MacAddr - hardware address of the adapter for this IP addr
+ IpIndex - Index of the IP Address in the IP Driver's address
+ table (used for setting address by DHCP)
+
+ EXIT: The device list in pConfig will be fully initialized
+
+ RETURNS: STATUS_SUCCESS if successful, error otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 14-Apr-1993 Created
+
+********************************************************************/
+
+NTSTATUS CreateDeviceObject(
+ IN tNBTCONFIG *pConfig,
+ IN ULONG IpAddr,
+ IN ULONG IpMask,
+ IN ULONG IpNameServer,
+ IN ULONG IpBackupServer,
+ IN ULONG IpDnsServer,
+ IN ULONG IpDnsBackupServer,
+ IN UCHAR MacAddr[],
+ IN UCHAR IpIndex
+ )
+{
+ NTSTATUS status;
+ tDEVICECONTEXT * pDeviceContext, *pDevtmp;
+ ULONG ulTmp ;
+ NCB * pNCB ;
+ DHCPNotify dn ;
+ PLIST_ENTRY pEntry;
+ ULONG Adapter;
+ ULONG PreviousNodeType;
+
+ CTEPagedCode();
+
+ pDeviceContext = CTEAllocInitMem(sizeof( tDEVICECONTEXT )) ;
+ if ( !pDeviceContext )
+ return STATUS_INSUFFICIENT_RESOURCES ;
+
+ //
+ // zero out the data structure
+ //
+ CTEZeroMemory( pDeviceContext, sizeof(tDEVICECONTEXT) );
+
+ // put a verifier value into the structure so that we can check that
+ // we are operating on the right data when the OS passes a device context
+ // to NBT
+ pDeviceContext->Verify = NBT_VERIFY_DEVCONTEXT;
+
+ //
+ // we aren't up yet: don't want ncb's coming in before we are ready!
+ //
+ pDeviceContext->fDeviceUp = FALSE;
+
+ // setup the spin lock);
+ CTEInitLock(&pDeviceContext->SpinLock);
+ pDeviceContext->LockNumber = DEVICE_LOCK;
+ pDeviceContext->lNameServerAddress = IpNameServer ;
+ pDeviceContext->lBackupServer = IpBackupServer ;
+ pDeviceContext->lDnsServerAddress = IpDnsServer ;
+ pDeviceContext->lDnsBackupServer = IpDnsBackupServer ;
+
+ // copy the mac addresss
+ CTEMemCopy(&pDeviceContext->MacAddress.Address[0], MacAddr, 6);
+
+ //
+ // if the node type is set to Bnode by default then switch to Hnode if
+ // there are any WINS servers configured.
+ //
+ PreviousNodeType = NodeType;
+
+ if ((NodeType & DEFAULT_NODE_TYPE) &&
+ (IpNameServer || IpBackupServer))
+ {
+ NodeType = MSNODE;
+ if (PreviousNodeType & PROXY)
+ NodeType |= PROXY;
+ }
+
+ //
+ // start the refresh timer (if we had already started it, this function
+ // just returns success)
+ //
+ status = StartRefreshTimer();
+
+ if ( !NT_SUCCESS( status ) )
+ {
+ CTEFreeMem( pDeviceContext ) ;
+ return( status ) ;
+ }
+
+
+ // initialize the pDeviceContext data structure. There is one of
+ // these data structured tied to each "device" that NBT exports
+ // to higher layers (i.e. one for each network adapter that it
+ // binds to.
+ // The initialization sets the forward link equal to the back link equal
+ // to the list head
+ InitializeListHead(&pDeviceContext->UpConnectionInUse);
+ InitializeListHead(&pDeviceContext->LowerConnection);
+ InitializeListHead(&pDeviceContext->LowerConnFreeHead);
+ InitializeListHead(&pDeviceContext->RcvAnyFromAnyHead);
+ InitializeListHead(&pDeviceContext->RcvDGAnyFromAnyHead);
+ InitializeListHead(&pDeviceContext->PartialRcvHead) ;
+
+ InitializeListHead(&pDeviceContext->DelayedEvents);
+
+ //
+ // Pick an adapter number that hasn't been used yet
+ //
+ Adapter = 1;
+ for ( pEntry = pConfig->DeviceContexts.Flink;
+ pEntry != &pConfig->DeviceContexts;
+ pEntry = pEntry->Flink )
+ {
+ pDevtmp = CONTAINING_RECORD( pEntry, tDEVICECONTEXT, Linkage );
+
+ if ( !(pDevtmp->AdapterNumber & Adapter) )
+ break;
+
+ Adapter <<= 1;
+ }
+
+ pDeviceContext->AdapterNumber = Adapter ;
+ pDeviceContext->IPIndex = IpIndex ;
+ NbtConfig.AdapterCount++ ;
+ if ( NbtConfig.AdapterCount > 1 )
+ {
+ NbtConfig.MultiHomed = TRUE ;
+ }
+
+ //
+ // Allocate our name table and session table watching for both a
+ // minimum and a maximum size.
+ //
+
+ pDeviceContext->cMaxNames = (UCHAR) min( pConfig->lRegistryMaxNames, MAX_NCB_NUMS ) ;
+
+ pDeviceContext->cMaxSessions = (UCHAR) min( pConfig->lRegistryMaxSessions, MAX_NCB_NUMS ) ;
+
+ //
+ // Add one to the table size for the zeroth element (used for permanent
+ // name in the name table). The user accessible table goes from 1 to n
+ //
+
+ if ( !(pDeviceContext->pNameTable = (tCLIENTELE**)
+ CTEAllocInitMem((USHORT)((pDeviceContext->cMaxNames+1) * sizeof(tADDRESSELE*)))) ||
+ !(pDeviceContext->pSessionTable = (tCONNECTELE**)
+ CTEAllocInitMem((pDeviceContext->cMaxSessions+1) * sizeof(tCONNECTELE*))))
+ {
+ return STATUS_INSUFFICIENT_RESOURCES ;
+ }
+
+ CTEZeroMemory( &pDeviceContext->pNameTable[0],
+ (pDeviceContext->cMaxNames+1)*sizeof(tCLIENTELE*)) ;
+ CTEZeroMemory( &pDeviceContext->pSessionTable[0],
+ (pDeviceContext->cMaxSessions+1)*sizeof(tCONNECTELE*) ) ;
+ pDeviceContext->iNcbNum = 1 ;
+ pDeviceContext->iLSNum = 1 ;
+
+ // add this new device context on to the List in the configuration
+ // data structure
+ InsertTailList(&pConfig->DeviceContexts,&pDeviceContext->Linkage);
+
+ //
+ // IpAddr can be 0 only in wfw case (when dhcp hasn't yet obtained one)
+ // (in case of chicago, we will never come this far if ipaddr is 0)
+ //
+ if (!IpAddr)
+ {
+ pDeviceContext->IpAddress = 0;
+ goto Skip_tdiaddr_init;
+ }
+
+ //
+ // open the required address objects with the underlying transport provider
+ //
+ status = NbtCreateAddressObjects(
+ IpAddr,
+ IpMask,
+ pDeviceContext);
+ if (!NT_SUCCESS(status))
+ {
+ KdPrint(("Failed to create the Address Object, status=%lC\n",status));
+ return(status);
+ }
+
+ // this call must converse with the transport underneath to create
+ // connections and associate them with the session address object
+ status = NbtInitConnQ(
+ &pDeviceContext->LowerConnFreeHead,
+ sizeof(tLOWERCONNECTION),
+ NBT_NUM_INITIAL_CONNECTIONS,
+ pDeviceContext);
+
+ if (!NT_SUCCESS(status))
+ {
+ CDbgPrint( DBGFLAG_ERROR,
+ ("CreateDeviceObject: NbtInitConnQ Failed!")) ;
+
+ return(status);
+ }
+
+ //
+ // Add the permanent name for this adapter
+ //
+ status = NbtAddPermanentName( pDeviceContext ) ;
+ if ( !NT_SUCCESS( status ))
+ {
+ return status ;
+ }
+
+Skip_tdiaddr_init:
+
+ //
+ // ok, we are ready to function! (we are setting this to TRUE even if
+ // there is no ipaddr yet (in case of wfw only) so that rdr,srv etc. can
+ // add names without error
+ //
+ pDeviceContext->fDeviceUp = TRUE;
+
+#ifndef CHICAGO
+ //
+ // Set up a DHCP notification for this device in case the IP address
+ // changes
+ //
+ dn.dn_pfnNotifyRoutine = AddrChngNotification ;
+ dn.dn_pContext = pDeviceContext ;
+
+ status = DhcpSetInfo( DHCP_SET_NOTIFY_HANDLER,
+ pDeviceContext->IPIndex,
+ &dn,
+ sizeof( dn )) ;
+ if ( status )
+ {
+ ASSERT(0);
+ CDbgPrint( DBGFLAG_ERROR,
+ ("CreateDeviceObject: Warning - Setting Dhcp notification handler failed")) ;
+ }
+#endif //!CHICAGO
+
+ return(STATUS_SUCCESS);
+}
+
+/*******************************************************************
+
+ NAME: GetDhcpOption
+
+ SYNOPSIS: Checks to see if the passed .ini parameter is a potential
+ DHCP option. If it is, it calls DHCP to get the option.
+
+ This routine is called when retrieving parameters from
+ the .ini file if the parameter is not found.
+
+ ENTRY: ValueName - String of .ini parameter name
+ DefaultValue - Value to return if not a DHCP option or
+ DHCP didn't have the option
+
+ RETURNS: DHCP option value or DefaultValue if an error occurred.
+ If the requested parameter is a string option (such as
+ scopeid), then a pointer to an allocated string is
+ returned.
+
+ NOTES: Name Server address is handled in GetNameServerAddress
+
+ HISTORY:
+ Johnl 17-Dec-1993 Created
+
+********************************************************************/
+
+#define OPTION_NETBIOS_SCOPE_OPTION 47
+#define OPTION_NETBIOS_NODE_TYPE 46
+#define OPTION_BROADCAST_ADDRESS 28
+
+struct
+{
+ PUCHAR pchParamName ;
+ ULONG DhcpOptionID ;
+} OptionMapping[] =
+ { { WS_NODE_TYPE, OPTION_NETBIOS_NODE_TYPE },
+ { NBT_SCOPEID, OPTION_NETBIOS_SCOPE_OPTION },
+ { WS_ALLONES_BCAST, OPTION_BROADCAST_ADDRESS }
+ } ;
+#define NUM_OPTIONS (sizeof(OptionMapping)/sizeof(OptionMapping[0]))
+
+
+ULONG GetDhcpOption( PUCHAR ValueName, ULONG DefaultValue )
+{
+ int i ;
+ ULONG Val ;
+ TDI_STATUS tdistatus ;
+ ULONG Size ;
+ INT OptionId ;
+ PUCHAR pStrVal ;
+
+ CTEPagedCode();
+
+ //
+ // Is this parameter a DHCP option?
+ //
+ for ( i = 0 ; i < NUM_OPTIONS ; i++ )
+ {
+ if ( !strcmp( OptionMapping[i].pchParamName, ValueName ))
+ goto FoundOption ;
+ }
+
+ return DefaultValue ;
+
+FoundOption:
+
+ switch ( OptionId = OptionMapping[i].DhcpOptionID )
+ {
+ case OPTION_NETBIOS_SCOPE_OPTION: // String options go here
+
+ //
+ // Get the size of the string resource, then get the option
+ //
+
+ Size = MAX_SCOPE_LENGTH+1 ;
+ pStrVal = CTEAllocInitMem( Size );
+ if (pStrVal == NULL)
+ {
+ DbgPrint("GetDhcpOption: failed to allocate memory") ;
+ return 0 ;
+ }
+
+ tdistatus = DhcpQueryOption( CurrentIP,
+ OptionId,
+ pStrVal,
+ &Size ) ;
+
+ if ( tdistatus == TDI_SUCCESS )
+ {
+ DbgPrint("GetDhcpOption: Successfully retrieved option ID ") ;
+ DbgPrintNum( OptionId ) ; DbgPrint("\r\n") ;
+ return (ULONG) pStrVal ;
+ }
+ else
+ {
+ DbgPrint("GetDhcpOption: returned error = 0x ") ;
+ DbgPrintNum( tdistatus ) ; DbgPrint("\r\n") ;
+ CTEMemFree( pStrVal ) ;
+ return 0 ;
+ }
+
+ default: // ULONG options go here
+ Size = sizeof( Val ) ;
+ tdistatus = DhcpQueryOption( CurrentIP,
+ OptionId,
+ &Val,
+ &Size ) ;
+ break ;
+ }
+
+ switch ( tdistatus )
+ {
+ case TDI_SUCCESS:
+ case TDI_BUFFER_OVERFLOW: // May be more then one, only take the 1st
+ DbgPrint("GetDhcpOption: Successfully retrieved option ID ") ;
+ DbgPrintNum( OptionId ) ; DbgPrint("\r\n") ;
+ return Val ;
+
+ case TDI_INVALID_PARAMETER: // Option not found
+ DbgPrint("GetDhcpOption: Failed to retrieve option ID ") ;
+ DbgPrintNum( OptionId ) ; DbgPrint("\r\n") ;
+ return DefaultValue ;
+
+ default:
+ ASSERT( FALSE ) ;
+ break ;
+ }
+
+ return DefaultValue ;
+}
+
+#ifndef CHICAGO
+#pragma END_INIT
+#endif
+
+
diff --git a/private/ntos/nbt/vxd/client.asm b/private/ntos/nbt/vxd/client.asm
new file mode 100644
index 000000000..0c44bbf79
--- /dev/null
+++ b/private/ntos/nbt/vxd/client.asm
@@ -0,0 +1,427 @@
+ page ,132
+ title client16.asm - 16-bit client support routines
+
+
+;**********************************************************************
+;** Microsoft Windows **
+;** Copyright(c) Microsoft Corp., 1993-1994 **
+;**********************************************************************
+;
+;
+; client16.asm
+;
+; VXDLIB routines for dealing with 16-bit clients.
+;
+; The following functions are exported by this module:
+;
+; VxdMapSegmentOffsetToFlat
+;
+;
+; FILE HISTORY:
+; Koti 14-Jun-1994 Stole from KeithMo
+;
+;
+
+.386p
+include vmm.inc
+include shell.inc
+include vwin32.inc
+include netvxd.inc
+include debug.inc
+
+
+;;;
+;;; Flag to _LinPage[Un]Lock.
+;;;
+
+ifdef CHICAGO
+VxdLinPageFlag equ PAGEMAPGLOBAL
+else ; !CHICAGO
+VxdLinPageFlag equ 0
+endif ; CHICAGO
+
+
+;***
+;*** Locked code segment.
+;***
+
+VXD_LOCKED_CODE_SEG
+
+;;;
+;;; Public functions.
+;;;
+
+;*******************************************************************
+;
+; NAME: VxdMapSegmentOffsetToFlat
+;
+; SYNOPSIS: Maps a segment/offset pair to the corresponding flat
+; pointer.
+;
+; ENTRY: VirtualHandle - VM handle.
+;
+; UserSegment - Segment value.
+;
+; UserOffset - Offset value
+;
+; RETURNS: LPVOID - The flat pointer, -1 if unsuccessful.
+;
+; NOTES: This routine was more-or-less stolen from the Map_Flat
+; source in dos386\vmm\vmmutil.asm.
+;
+; HISTORY:
+; KeithMo 27-Jan-1994 Created.
+;
+;********************************************************************
+BeginProc _VxdMapSegmentOffsetToFlat, PUBLIC, CCALL, ESP
+
+ArgVar VirtualHandle, DWORD
+ArgVar UserSegment, DWORD
+ArgVar UserOffset, DWORD
+
+ EnterProc
+ SaveReg <ebx, ecx, edx, esi>
+
+;;;
+;;; Capture the parameters.
+;;;
+
+ mov ebx, VirtualHandle ; (EBX) = VM handle
+ movzx eax, word ptr UserSegment ; (EAX) = segment
+ movzx esi, word ptr UserOffset ; (ESI) = offset
+
+;;;
+;;; Short-circuit for NULL pointer. This is OK.
+;;;
+
+ or eax, eax
+ jz vmsotf_Exit
+
+;;;
+;;; Determine if the current virtual machine is running in V86
+;;; mode or protected mode.
+;;;
+
+ test [ebx.CB_VM_Status], VMStat_PM_Exec
+ jz vmsotf_V86Mode
+
+;;;
+;;; The target virtual machine is in protected mode. Map the
+;;; selector to a flat pointer, then add the offset.
+;;;
+
+ VMMCall _SelectorMapFlat <ebx, eax, 0>
+ cmp eax, 0FFFFFFFFh
+ je vmsotf_Exit
+
+ add eax, esi
+
+;;;
+;;; If the pointer is within the first 1Meg+64K, add in the
+;;; high-linear offset.
+;;;
+
+ cmp eax, 00110000h
+ jae short vmsotf_Exit
+
+vmsotf_AddHighLinear:
+
+ add eax, [ebx.CB_High_Linear]
+
+;;;
+;;; Cleanup stack & return.
+;;;
+
+vmsotf_Exit:
+
+ RestoreReg <esi, edx, ecx, ebx>
+ LeaveProc
+ Return
+
+;;;
+;;; The target virtual machine is in V86 mode. Map the segment/offset
+;;; pair to a linear address.
+;;;
+
+vmsotf_V86Mode:
+
+ shl eax, 4
+ add eax, esi
+ jmp vmsotf_AddHighLinear
+
+EndProc _VxdMapSegmentOffsetToFlat
+
+
+;*******************************************************************
+;
+; NAME: VxdLockBuffer
+;
+; SYNOPSIS: Locks a user-mode buffer so it may be safely accessed
+; from ring 0.
+;
+; ENTRY: Buffer - Starting virtual address of user-mode buffer.
+;
+; BufferLength - Length (in BYTEs) of user-mode buffer.
+;
+; RETURN: LPVOID - Global locked address if successful,
+; NULL if not.
+;
+; HISTORY:
+; KeithMo 10-Nov-1993 Created.
+;
+;********************************************************************
+BeginProc _VxdLockBuffer, PUBLIC, CCALL, ESP
+
+ArgVar Buffer, DWORD
+ArgVar BufferLength, DWORD
+
+ EnterProc
+ SaveReg <ebx, edi, esi>
+
+;;;
+;;; Grab parameters from stack.
+;;;
+
+ mov eax, Buffer ; User-mode buffer address.
+ mov ebx, BufferLength ; Buffer length.
+
+;;;
+;;; Short-circuit for NULL buffer or zero length.
+;;;
+
+ or eax, eax
+ jz lub_Exit
+ or ebx, ebx
+ jz lub_Exit
+
+;;;
+;;; Calculate the starting page number & number of pages to lock.
+;;;
+
+ movzx ecx, ax
+ and ch, 0Fh ; ecx = offset within first page.
+ mov esi, ecx ; save it for later
+ add ebx, ecx
+ add ebx, 0FFFh
+ shr ebx, 12 ; ebx = number of pages to lock.
+ shr eax, 12 ; eax = starting page number.
+
+;;;
+;;; Ask VMM to lock the buffer.
+;;;
+
+ VMMCall _LinPageLock, <eax, ebx, VxdLinPageFlag>
+ or eax, eax
+ jz lub_Failure
+
+ifdef CHICAGO
+ add eax, esi ; add offset into first page.
+else ; !CHICAGO
+ mov eax, Buffer ; retrieve original address.
+endif ; CHICAGO
+
+;;;
+;;; Common exit path. Cleanup stack & return.
+;;;
+
+lub_Exit:
+
+ RestoreReg <esi, edi, ebx>
+ LeaveProc
+ Return
+
+;;;
+;;; LinPageLock failure.
+;;;
+
+lub_Failure:
+
+ Trace_Out "VxdLockBuffer: _LinPageLock failed"
+ xor eax, eax
+ jmp lub_Exit
+
+EndProc _VxdLockBuffer
+
+
+;*******************************************************************
+;
+; NAME: VxdUnlockBuffer
+;
+; SYNOPSIS: Unlocks a user-mode buffer locked with LockUserBuffer.
+;
+; ENTRY: Buffer - Starting virtual address of user-mode buffer.
+;
+; BufferLength - Length (in BYTEs) of user-mode buffer.
+;
+; RETURN: DWORD - !0 if successful, 0 if not.
+;
+; HISTORY:
+; KeithMo 10-Nov-1993 Created.
+;
+;********************************************************************
+BeginProc _VxdUnlockBuffer, PUBLIC, CCALL, ESP
+
+ArgVar Buffer, DWORD
+ArgVar BufferLength, DWORD
+
+ EnterProc
+ SaveReg <ebx, edi, esi>
+
+;;;
+;;; Grab parameters from stack.
+;;;
+
+ mov eax, Buffer ; User-mode buffer address.
+ mov ebx, BufferLength ; Buffer length.
+
+;;;
+;;; Short-circuit for NULL buffer or zero length.
+;;;
+
+ or eax, eax
+ jz uub_Success
+ or ebx, ebx
+ jz uub_Success
+
+;;;
+;;; Calculate the starting page number & number of pages to unlock.
+;;;
+
+ movzx ecx, ax
+ and ch, 0Fh ; ecx = offset within first page.
+ add ebx, ecx
+ add ebx, 0FFFh
+ shr ebx, 12 ; ebx = number of pages to lock.
+ shr eax, 12 ; eax = starting page number.
+
+;;;
+;;; Ask VMM to unlock the buffer.
+;;;
+
+ VMMCall _LinPageUnLock, <eax, ebx, VxdLinPageFlag>
+ or eax, eax
+ jz uub_Failure
+
+uub_Success:
+
+ mov eax, 1 ; !0 == success
+
+;;;
+;;; Common exit path. Cleanup stack & return.
+;;;
+
+uub_Exit:
+
+ RestoreReg <esi, edi, ebx>
+ LeaveProc
+ Return
+
+;;;
+;;; LinPageUnLock failure.
+;;;
+
+uub_Failure:
+
+ Trace_Out "VxdUnlockBuffer: _LinPageUnlock failed"
+ xor eax, eax
+ jmp uub_Exit
+
+EndProc _VxdUnlockBuffer
+
+
+;
+; BUGBUG: VxdValidateBuffer is currently not used. Unifdef it if needed
+;
+
+
+;*******************************************************************
+;
+; NAME: VxdValidateBuffer
+;
+; SYNOPSIS: Validates that all pages within the given buffer are
+; valid.
+;
+; ENTRY: Buffer - Starting virtual address of user-mode buffer.
+;
+; BufferLength - Length (in BYTEs) of user-mode buffer.
+;
+; RETURN: BOOL - TRUE if all pages in buffer are valid, FALSE
+; otherwise.
+;
+; HISTORY:
+; KeithMo 20-May-1994 Created.
+;
+;********************************************************************
+BeginProc _VxdValidateBuffer, PUBLIC, CCALL, ESP
+
+ArgVar Buffer, DWORD
+ArgVar BufferLength, DWORD
+
+ EnterProc
+ SaveReg <ebx, edi, esi>
+
+;;;
+;;; Grab parameters from stack.
+;;;
+
+ mov eax, Buffer ; User-mode buffer address.
+ mov ebx, BufferLength ; Buffer length.
+
+;;;
+;;; Short-circuit for NULL buffer or zero length.
+;;;
+
+ or eax, eax
+ jz vub_Success
+ or ebx, ebx
+ jz vub_Success
+
+;;;
+;;; Calculate the starting page number & number of pages to validate.
+;;;
+
+ movzx ecx, ax
+ and ch, 0Fh ; ecx = offset within first page.
+ add ebx, ecx
+ add ebx, 0FFFh
+ shr ebx, 12 ; ebx = number of pages to check.
+ shr eax, 12 ; eax = starting page number.
+ mov ecx, ebx ; save page count
+
+;;;
+;;; Ask VMM to validate the buffer.
+;;;
+
+ VMMCall _PageCheckLinRange, <eax, ebx, 0>
+ cmp eax, ecx
+ jne vub_Failure
+
+vub_Success:
+
+ mov eax, 1 ; TRUE == success.
+
+;;;
+;;; Common exit path. Cleanup stack & return.
+;;;
+
+vub_Exit:
+
+ RestoreReg <esi, edi, ebx>
+ LeaveProc
+ Return
+
+;;;
+;;; _PageCheckLinRange failure.
+;;;
+
+vub_Failure:
+
+ xor eax, eax
+ jmp vub_Exit
+
+EndProc _VxdValidateBuffer
+
+VXD_LOCKED_CODE_ENDS
+
+
+END
diff --git a/private/ntos/nbt/vxd/ctimer.c b/private/ntos/nbt/vxd/ctimer.c
new file mode 100644
index 000000000..29cca3179
--- /dev/null
+++ b/private/ntos/nbt/vxd/ctimer.c
@@ -0,0 +1,237 @@
+/**********************************************************************/
+/** Microsoft Windows **/
+/** Copyright(c) Microsoft Corp., 1993 **/
+/**********************************************************************/
+
+/*
+
+ Timer.c
+
+ This module checks for active sessions on all adapters for send/receive
+ NCBs that have timed out.
+
+ A single timer is used for all adapters.
+
+ If a send times out, then the session will be aborted.
+
+ FILE HISTORY:
+ Johnl 23-Sep-1993 Created
+
+*/
+
+#include <nbtprocs.h>
+#include <ctemacro.h>
+
+CTETimer TimeoutTimer ;
+
+/*******************************************************************
+
+ NAME: CheckForTimedoutNCBs
+
+ SYNOPSIS: Traverses list of all send/receive NCBs checking for
+ any that have reached their timeout point every half
+ second.
+
+ ENTRY: pEvent - Not used
+ pCont - Not used
+
+ RETURNS: TRUE if the timer successfully started, FALSE otherwise
+
+ NOTES: This is a self perpetuating function, each time it is called,
+ it schedules the timer again for a 1/2 second later to
+ call itself.
+
+ To get it going, it should be called once during
+ initialization
+
+ HISTORY:
+ Johnl 23-Sep-1993 Created
+
+********************************************************************/
+
+BOOL CheckForTimedoutNCBs( CTEEvent *pCTEEvent, PVOID pCont )
+{
+ tNAMEADDR * pNameAddr ;
+ tCLIENTELE * pClientEle ;
+ tCONNECTELE * pConnectEle ;
+ LIST_ENTRY * pEntry ;
+ LIST_ENTRY * pEntryClient ;
+ LIST_ENTRY * pEntryConn ;
+ LIST_ENTRY * pEntryRcv ;
+
+ //
+ // Look for Receive NCBs first
+ //
+ for ( pEntry = NbtConfig.AddressHead.Flink ;
+ pEntry != &NbtConfig.AddressHead ;
+ pEntry = pEntry->Flink )
+ {
+ PLIST_ENTRY pEntryClient ;
+ tADDRESSELE * pAddrEle = CONTAINING_RECORD( pEntry,
+ tADDRESSELE,
+ Linkage ) ;
+ ASSERT( pAddrEle->Verify == NBT_VERIFY_ADDRESS ) ;
+
+ for ( pEntryClient = pAddrEle->ClientHead.Flink ;
+ pEntryClient != &pAddrEle->ClientHead ;
+ pEntryClient = pEntryClient->Flink )
+ {
+ tCLIENTELE * pClientEle = CONTAINING_RECORD( pEntryClient,
+ tCLIENTELE,
+ Linkage ) ;
+ PLIST_ENTRY pEntryConn ;
+ ASSERT( pClientEle->Verify == NBT_VERIFY_CLIENT ||
+ pClientEle->Verify == NBT_VERIFY_CLIENT_DOWN ) ;
+
+ for ( pEntryConn = pClientEle->ConnectActive.Flink ;
+ pEntryConn != &pClientEle->ConnectActive ;
+ pEntryConn = pEntryConn->Flink )
+ {
+ PRCV_CONTEXT prcvCont ;
+ pConnectEle = CONTAINING_RECORD( pEntryConn,
+ tCONNECTELE,
+ Linkage ) ;
+ ASSERT( pConnectEle->Verify == NBT_VERIFY_CONNECTION ||
+ pConnectEle->Verify == NBT_VERIFY_CONNECTION_DOWN ) ;
+
+ if ( pConnectEle->RTO == NCB_INFINITE_TIME_OUT ||
+ pConnectEle->state != NBT_SESSION_UP ||
+ IsListEmpty( &pConnectEle->RcvHead ) )
+ {
+ continue ;
+ }
+
+ //
+ // Note that we only check the first receive buffer because
+ // the timeout is for the next receive indication (and not
+ // how long this NCB has been waiting).
+ //
+ pEntryRcv = pConnectEle->RcvHead.Flink ;
+ prcvCont = CONTAINING_RECORD( pEntryRcv, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ if ( prcvCont->RTO == NCB_TIMED_OUT )
+ {
+ RemoveEntryList( &prcvCont->ListEntry ) ;
+ CTEIoComplete( prcvCont->pNCB, STATUS_TIMEOUT, 0 ) ;
+ }
+ else
+ {
+ prcvCont->RTO-- ;
+ }
+ } // ConnectActive
+ } // Client
+ } // Address
+
+ //
+ // Now look for Send NCB time outs. Only connections that specified
+ // a timeout will be put on this list.
+ //
+ for ( pEntry = NbtConfig.SendTimeoutHead.Flink ;
+ pEntry != &NbtConfig.SendTimeoutHead ;
+ )
+ {
+ PSEND_CONTEXT pSendCont ;
+
+ pSendCont = CONTAINING_RECORD( pEntry, SEND_CONTEXT, ListEntry ) ;
+ pEntry = pEntry->Flink ; // get the next one
+
+ pSendCont->STO-- ;
+ if ( pSendCont->STO == NCB_TIMED_OUT )
+ {
+ //
+ // Assumes pSendCont is stored in ncb_reserve field of NCB
+ // This will remove it from the timeout list also.
+ //
+ CTEIoComplete( CONTAINING_RECORD( pSendCont, NCB, ncb_reserve ),
+ STATUS_TIMEOUT,
+ 0 ) ;
+ // the above CTEIoComplete will trigger events from the transport
+ // which could modify the SendTimeout list before we reach this
+ // point. Best just to wait until things clear up.
+ break;
+ }
+ }
+
+ //
+ // Restart the timer for a half second from now
+ //
+ CTEInitTimer( &TimeoutTimer ) ;
+ return !!CTEStartTimer( &TimeoutTimer, 500, CheckForTimedoutNCBs, NULL ) ;
+}
+
+
+/*******************************************************************
+
+ NAME: StartRefreshTimer
+
+ SYNOPSIS: Start the refresh timer
+ This function was necessary because of this scenario:
+ No node type was defined in registry, so we defaulted to
+ BNODE and didn't start refresh timer.
+ Now, while we are still coming up, dhcp tells us we are
+ MSNODE. Shouldn't we start the refresh timer?
+ That's why this function.
+
+ HISTORY:
+ Koti 9-Jun-1994 Created
+
+********************************************************************/
+
+NTSTATUS StartRefreshTimer( VOID )
+{
+
+ NTSTATUS status = STATUS_SUCCESS;
+ tTIMERQENTRY *pTimerEntry;
+
+ //
+ // make sure it's not bnode, and that timer really needs to be started
+ //
+ if (!(NodeType & BNODE) && (!NbtConfig.pRefreshTimer))
+ {
+
+ // the initial refresh rate until we can contact the name server
+ NbtConfig.MinimumTtl = NBT_INITIAL_REFRESH_TTL;
+ NbtConfig.sTimeoutCount = 0;
+
+ status = StartTimer(
+ NbtConfig.InitialRefreshTimeout,
+ NULL, // context value
+ NULL, // context2 value
+ RefreshTimeout,
+ NULL,
+ NULL,
+ 0,
+ &pTimerEntry);
+
+ if ( !NT_SUCCESS( status ) )
+ return status ;
+
+ NbtConfig.pRefreshTimer = pTimerEntry;
+ }
+
+ return(STATUS_SUCCESS);
+}
+
+
+#ifdef CHICAGO
+
+/*******************************************************************
+
+ NAME: StopTimeoutTimer
+
+ SYNOPSIS: Stops the timer that was set in CheckForTimedoutNCBs.
+ This is needed only for Chicago which can dynamically
+ unload vnbt.
+
+ HISTORY:
+ Koti 23-May-1994 Created
+
+********************************************************************/
+
+VOID StopTimeoutTimer( VOID )
+{
+ CTEStopTimer( &TimeoutTimer );
+}
+
+#endif
diff --git a/private/ntos/nbt/vxd/cvxdfile.asm b/private/ntos/nbt/vxd/cvxdfile.asm
new file mode 100644
index 000000000..451f18501
--- /dev/null
+++ b/private/ntos/nbt/vxd/cvxdfile.asm
@@ -0,0 +1,186 @@
+;/**********************************************************************/
+;/** Microsoft Windows/NT **/
+;/** Copyright(c) Microsoft Corp., 1994 **/
+;/**********************************************************************/
+
+;/*
+; cvxdFile.asm
+;
+; Contains simple VXD File I/O routines (that use VxdInt 21h macro)
+; for dhcp.bin support
+;
+; FILE HISTORY:
+; madana 07-May-1994 Created
+; koti 10-Oct-1994 Copied over/modified for vnbt
+;
+;*/
+
+ .386p
+ include vmm.inc
+ include v86mmgr.inc
+ include dosmgr.inc
+ include opttest.inc
+ include netvxd.inc
+ include debug.inc
+ include pageable.inc
+
+EXTRN _fInInit:DWORD
+EXTRN _GetInDosFlag:NEAR
+
+
+;****************************************************************************
+;** PushState Macro
+;
+; Saves the client state.
+;
+PushState MACRO
+
+ push edi
+ push esi
+ push ebx
+
+ mov ecx, 0
+ VMMCall Begin_Critical_Section
+
+ENDM
+
+;****************************************************************************
+;** PopState Macro
+;
+; Restores client state.
+;
+PopState MACRO
+
+ VMMCall End_Critical_Section
+
+ pop ebx
+ pop esi
+ pop edi
+
+ENDM
+
+NBT_PAGEABLE_CODE_SEG
+
+;****************************************************************************
+;** _VxdFileOpen
+;
+; Opens a file
+;
+; Entry: [ESP+4] - Pointer to full path of file, path must be flat
+; pointer.
+;
+; Exit: EAX will contain a handle to the openned file
+;
+BeginProc _VxdFileOpen
+
+ PushState ; This pushes lots of crap
+
+ mov edx, [esp+16] ; move flat pointer file name
+ mov eax, 3d02h ; Open file, read/write, share
+
+ VxDInt 21h
+
+ jc VFO_6 ; Carry set if error
+ jmp VFO_10 ; successful file open, eax has file handle
+
+VFO_6:
+; Debug_Out "VxdFileOpen failed, error #EAX"
+ mov eax, 0 ; Failed to open the file
+
+VFO_10:
+ PopState
+ ret
+
+EndProc _VxdFileOpen
+
+
+;****************************************************************************
+;** _VxdFileRead
+;
+; Reads x bytes from a previously openned file
+;
+; Entry: [ESP+4] - Handle from _VxdFileOpen
+; [ESP+8] - Count of bytes to read
+; [ESP+12]- flat pointer to destination buffer
+;
+; Exit: EAX will contain the number of bytes read, 0 if EOF or
+; an error occurred.
+;
+BeginProc _VxdFileRead
+
+ PushState ; Pushes lots of crap
+
+ mov ebx, [esp+16] ; File Handle
+ mov ecx, [esp+20] ; Bytes to read
+ mov edx, [esp+24] ; flat buffer pointer
+ mov eax, 3f00h
+
+ VxDInt 21h
+
+ jc VFR_6 ; Carry set if error
+ jmp VFR_7 ; successful file open, eax has bytes read
+
+VFR_6:
+; Debug_Out "VxdFileRead failed"
+ mov eax, 0 ; Failed to read the file
+VFR_7:
+ PopState
+ ret
+
+EndProc _VxdFileRead
+
+;****************************************************************************
+;** _VxdFileClose
+;
+; Closes a file openned with VxdOpenFile
+;
+; Entry: [ESP+4] - Handle from _VxdFileOpen
+;
+BeginProc _VxdFileClose
+
+ PushState ; Pushes lots of crap
+
+ mov ebx, [esp+16] ; File Handle
+ mov eax, 3e00h
+
+ VxDInt 21h
+
+ jc VFCL_6 ; Carry set if error
+ jmp VFCL_7 ; successful set.
+
+VFCL_6:
+ Debug_Out "VxdFileClose - Read failed"
+ mov eax, 0 ; Failed to close the file
+VFCL_7:
+ PopState
+ ret
+
+EndProc _VxdFileClose
+
+;****************************************************************************
+;** _VxdWindowsPath
+;
+; Gets a pointer to (null-terminated) path to the windows directory
+;
+; This is an Init time only routine
+;
+; Entry: nothing
+;
+; Exit: pointer to path to windows directory
+;
+BeginProc _VxdWindowsPath
+ PushState ; Pushes lots of crap
+
+ VmmCall Get_Config_Directory
+
+ mov eax, edx ; path is returned in edx
+
+ PopState ; now pop all that crap
+
+ ret
+
+EndProc _VxdWindowsPath
+
+NBT_PAGEABLE_CODE_ENDS
+
+END
diff --git a/private/ntos/nbt/vxd/cxport.inc b/private/ntos/nbt/vxd/cxport.inc
new file mode 100644
index 000000000..edbc6d2a2
--- /dev/null
+++ b/private/ntos/nbt/vxd/cxport.inc
@@ -0,0 +1,4 @@
+;; Dummy include file so we can build COFF version of
+;; "cxport.obj."
+;;
+;; Eventually, this may become obsolete.
diff --git a/private/ntos/nbt/vxd/depend.mk b/private/ntos/nbt/vxd/depend.mk
new file mode 100644
index 000000000..5dba4a995
--- /dev/null
+++ b/private/ntos/nbt/vxd/depend.mk
@@ -0,0 +1,1279 @@
+#********************************************************************
+#** Copyright(c) Microsoft Corp., 1993 **
+#********************************************************************
+$(SNOVNBTOBJD)/chicasm.obj $(SNODVNBTOBJD)/chicasm.obj $(VNBTSRC)/chicasm.lst: \
+ $(VNBTSRC)/chicasm.asm ../blt/netvxd.inc ../blt/vdhcp.inc \
+ $(VNBTSRC)/vnbtd.inc $(IMPORT)/win32/ddk/inc/debug.inc \
+ $(IMPORT)/wininc/dosmgr.inc \
+ $(IMPORT)/wininc/vnetbios.inc $(NDIS3INC)/vmm.inc \
+ $(CHICAGO)/tcp/inc/vip.inc $(CHICAGO)/tcp/inc/vtdi.inc
+
+$(SNOVNBTOBJD)/client.obj $(SNODVNBTOBJD)/client.obj $(VNBTSRC)/client.lst: \
+ $(VNBTSRC)/client.asm ../blt/netvxd.inc \
+ $(IMPORT)/win32/ddk/inc/debug.inc \
+ $(IMPORT)/win32/ddk/inc/shell.inc \
+ $(IMPORT)/win32/ddk/inc/shellfsc.inc \
+ $(NDIS3INC)/vmm.inc $(NDIS3INC)/vwin32.inc
+
+$(SNOVNBTOBJD)/cvxdfile.obj $(SNODVNBTOBJD)/cvxdfile.obj $(VNBTSRC)/cvxdfile.lst: \
+ $(VNBTSRC)/cvxdfile.asm ../blt/netvxd.inc \
+ $(IMPORT)/win32/ddk/inc/debug.inc \
+ $(IMPORT)/win32/ddk/inc/opttest.inc \
+ $(IMPORT)/wininc/dosmgr.inc \
+ $(IMPORT)/wininc/v86mmgr.inc $(NDIS3INC)/vmm.inc
+
+$(SNOVNBTOBJD)/vfirst.obj $(SNODVNBTOBJD)/vfirst.obj $(VNBTSRC)/vfirst.lst: \
+ $(VNBTSRC)/vfirst.asm
+
+$(SNOVNBTOBJD)/vnbtd.obj $(SNODVNBTOBJD)/vnbtd.obj $(VNBTSRC)/vnbtd.lst: \
+ $(VNBTSRC)/vnbtd.asm ../blt/netvxd.inc ../blt/vdhcp.inc $(VNBTSRC)/vnbtd.inc \
+ $(IMPORT)/win32/ddk/inc/debug.inc \
+ $(IMPORT)/wininc/dosmgr.inc \
+ $(IMPORT)/wininc/vnetbios.inc $(NDIS3INC)/vmm.inc \
+ $(CHICAGO)/tcp/inc/vtdi.inc
+
+$(SNOVNBTOBJD)/vxdfile.obj $(SNODVNBTOBJD)/vxdfile.obj $(VNBTSRC)/vxdfile.lst: \
+ $(VNBTSRC)/vxdfile.asm ../blt/netvxd.inc \
+ $(IMPORT)/win32/ddk/inc/debug.inc \
+ $(IMPORT)/win32/ddk/inc/opttest.inc \
+ $(IMPORT)/wininc/dosmgr.inc \
+ $(IMPORT)/wininc/v86mmgr.inc $(NDIS3INC)/vmm.inc
+
+$(SNOVNBTOBJD)/vxdstub.obj $(SNODVNBTOBJD)/vxdstub.obj $(VNBTSRC)/vxdstub.lst: \
+ $(VNBTSRC)/vxdstub.asm $(IMPORT)/wininc/INT2FAPI.INC
+
+$(SNOVNBTOBJD)/wfwasm.obj $(SNODVNBTOBJD)/wfwasm.obj $(VNBTSRC)/wfwasm.lst: \
+ $(VNBTSRC)/wfwasm.asm ../blt/netvxd.inc ../blt/vdhcp.inc $(VNBTSRC)/vnbtd.inc \
+ $(IMPORT)/win32/ddk/inc/debug.inc \
+ $(IMPORT)/wininc/dosmgr.inc \
+ $(IMPORT)/wininc/vnetbios.inc $(NDIS3INC)/vmm.inc \
+ $(CHICAGO)/tcp/inc/vtdi.inc
+
+$(CHIVNBTOBJD)/chicasm.obj $(CHIDVNBTOBJD)/chicasm.obj $(VNBTSRC)/chicasm.lst: \
+ $(VNBTSRC)/chicasm.asm ../blt/vdhcp.inc $(VNBTSRC)/vnbtd.inc \
+ $(CHICAGO)/dev/ddk/inc/debug.inc $(CHICAGO)/dev/ddk/inc/dosmgr.inc \
+ $(CHICAGO)/dev/ddk/inc/netvxd.inc $(CHICAGO)/dev/ddk/inc/vmm.inc \
+ $(CHICAGO)/dev/ddk/inc/vnetbios.inc $(CHICAGO)/tcp/inc/vip.inc \
+ $(CHICAGO)/tcp/inc/vtdi.inc
+
+$(CHIVNBTOBJD)/client.obj $(CHIDVNBTOBJD)/client.obj $(VNBTSRC)/client.lst: \
+ $(VNBTSRC)/client.asm $(CHICAGO)/dev/ddk/inc/debug.inc \
+ $(CHICAGO)/dev/ddk/inc/netvxd.inc $(CHICAGO)/dev/ddk/inc/shell.inc \
+ $(CHICAGO)/dev/ddk/inc/vmm.inc $(CHICAGO)/dev/ddk/inc/vwin32.inc
+
+$(CHIVNBTOBJD)/cvxdfile.obj $(CHIDVNBTOBJD)/cvxdfile.obj $(VNBTSRC)/cvxdfile.lst: \
+ $(VNBTSRC)/cvxdfile.asm $(CHICAGO)/dev/ddk/inc/debug.inc \
+ $(CHICAGO)/dev/ddk/inc/dosmgr.inc $(CHICAGO)/dev/ddk/inc/netvxd.inc \
+ $(CHICAGO)/dev/ddk/inc/opttest.inc $(CHICAGO)/dev/ddk/inc/v86mmgr.inc \
+ $(CHICAGO)/dev/ddk/inc/vmm.inc
+
+$(CHIVNBTOBJD)/vfirst.obj $(CHIDVNBTOBJD)/vfirst.obj $(VNBTSRC)/vfirst.lst: \
+ $(VNBTSRC)/vfirst.asm
+
+$(CHIVNBTOBJD)/vnbtd.obj $(CHIDVNBTOBJD)/vnbtd.obj $(VNBTSRC)/vnbtd.lst: \
+ $(VNBTSRC)/vnbtd.asm ../blt/vdhcp.inc $(VNBTSRC)/vnbtd.inc \
+ $(CHICAGO)/dev/ddk/inc/debug.inc $(CHICAGO)/dev/ddk/inc/dosmgr.inc \
+ $(CHICAGO)/dev/ddk/inc/netvxd.inc $(CHICAGO)/dev/ddk/inc/vmm.inc \
+ $(CHICAGO)/dev/ddk/inc/vnetbios.inc $(CHICAGO)/tcp/inc/vtdi.inc
+
+$(CHIVNBTOBJD)/vxdfile.obj $(CHIDVNBTOBJD)/vxdfile.obj $(VNBTSRC)/vxdfile.lst: \
+ $(VNBTSRC)/vxdfile.asm $(CHICAGO)/dev/ddk/inc/debug.inc \
+ $(CHICAGO)/dev/ddk/inc/dosmgr.inc $(CHICAGO)/dev/ddk/inc/netvxd.inc \
+ $(CHICAGO)/dev/ddk/inc/opttest.inc $(CHICAGO)/dev/ddk/inc/v86mmgr.inc \
+ $(CHICAGO)/dev/ddk/inc/vmm.inc
+
+$(CHIVNBTOBJD)/vxdstub.obj $(CHIDVNBTOBJD)/vxdstub.obj $(VNBTSRC)/vxdstub.lst: \
+ $(VNBTSRC)/vxdstub.asm $(CHICAGO)/dev/ddk/inc/INT2FAPI.INC
+
+$(CHIVNBTOBJD)/wfwasm.obj $(CHIDVNBTOBJD)/wfwasm.obj $(VNBTSRC)/wfwasm.lst: \
+ $(VNBTSRC)/wfwasm.asm ../blt/vdhcp.inc $(VNBTSRC)/vnbtd.inc \
+ $(CHICAGO)/dev/ddk/inc/debug.inc $(CHICAGO)/dev/ddk/inc/dosmgr.inc \
+ $(CHICAGO)/dev/ddk/inc/netvxd.inc $(CHICAGO)/dev/ddk/inc/vmm.inc \
+ $(CHICAGO)/dev/ddk/inc/vnetbios.inc $(CHICAGO)/tcp/inc/vtdi.inc
+
+$(SNOVNBTOBJD)/chic.obj $(SNODVNBTOBJD)/chic.obj $(VNBTSRC)/chic.lst: \
+ $(VNBTSRC)/chic.c ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h ../blt/dhcpinfo.h $(INC)/ctemacro.h \
+ $(INC)/debug.h $(INC)/nbtinfo.h $(INC)/nbtnt.h $(INC)/nbtprocs.h \
+ $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h $(INC)/vxddebug.h \
+ $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h $(CHICAGO)/tcp/h/tdivxd.h \
+ $(BASEDIR)/private/inc/ipinfo.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdiinfo.h \
+ $(BASEDIR)/private/inc/tdikrnl.h $(BASEDIR)/private/inc/tdistat.h \
+ $(BASEDIR)/public/sdk/inc/alphaops.h $(BASEDIR)/public/sdk/inc/crt/ctype.h \
+ $(BASEDIR)/public/sdk/inc/crt/excpt.h $(BASEDIR)/public/sdk/inc/crt/limits.h \
+ $(BASEDIR)/public/sdk/inc/crt/stdarg.h $(BASEDIR)/public/sdk/inc/crt/stddef.h \
+ $(BASEDIR)/public/sdk/inc/crt/string.h $(BASEDIR)/public/sdk/inc/devioctl.h \
+ $(BASEDIR)/public/sdk/inc/lintfunc.hxx $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/netevent.h \
+ $(BASEDIR)/public/sdk/inc/nt.h $(BASEDIR)/public/sdk/inc/ntalpha.h \
+ $(BASEDIR)/public/sdk/inc/ntconfig.h $(BASEDIR)/public/sdk/inc/ntddtdi.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntppc.h $(BASEDIR)/public/sdk/inc/ntpsapi.h \
+ $(BASEDIR)/public/sdk/inc/ntregapi.h $(BASEDIR)/public/sdk/inc/ntrtl.h \
+ $(BASEDIR)/public/sdk/inc/ntseapi.h $(BASEDIR)/public/sdk/inc/ntstatus.h \
+ $(BASEDIR)/public/sdk/inc/ntxcapi.h $(BASEDIR)/public/sdk/inc/poppack.h \
+ $(BASEDIR)/public/sdk/inc/ppcinst.h $(BASEDIR)/public/sdk/inc/pshpack1.h \
+ $(BASEDIR)/public/sdk/inc/pshpack4.h $(BASEDIR)/public/sdk/inc/windef.h \
+ $(BASEDIR)/public/sdk/inc/winerror.h $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/fileio.obj $(SNODVNBTOBJD)/fileio.obj $(VNBTSRC)/fileio.lst: \
+ $(VNBTSRC)/fileio.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/hosts.h \
+ $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h \
+ $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(CHICAGO)/tcp/h/oscfg.h $(CHICAGO)/tcp/h/tdivxd.h \
+ $(BASEDIR)/private/inc/nbtioctl.h $(BASEDIR)/private/inc/nettypes.h \
+ $(BASEDIR)/private/inc/packoff.h $(BASEDIR)/private/inc/packon.h \
+ $(BASEDIR)/private/inc/sockets/netinet/in.h $(BASEDIR)/private/inc/status.h \
+ $(BASEDIR)/private/inc/sys/snet/ip_proto.h $(BASEDIR)/private/inc/tdi.h \
+ $(BASEDIR)/private/inc/tdikrnl.h $(BASEDIR)/private/inc/tdistat.h \
+ $(BASEDIR)/public/sdk/inc/alphaops.h $(BASEDIR)/public/sdk/inc/crt/ctype.h \
+ $(BASEDIR)/public/sdk/inc/crt/excpt.h $(BASEDIR)/public/sdk/inc/crt/limits.h \
+ $(BASEDIR)/public/sdk/inc/crt/stdarg.h $(BASEDIR)/public/sdk/inc/crt/stddef.h \
+ $(BASEDIR)/public/sdk/inc/crt/string.h $(BASEDIR)/public/sdk/inc/devioctl.h \
+ $(BASEDIR)/public/sdk/inc/lintfunc.hxx $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/netevent.h \
+ $(BASEDIR)/public/sdk/inc/nt.h $(BASEDIR)/public/sdk/inc/ntalpha.h \
+ $(BASEDIR)/public/sdk/inc/ntconfig.h $(BASEDIR)/public/sdk/inc/ntddtdi.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntppc.h $(BASEDIR)/public/sdk/inc/ntpsapi.h \
+ $(BASEDIR)/public/sdk/inc/ntregapi.h $(BASEDIR)/public/sdk/inc/ntrtl.h \
+ $(BASEDIR)/public/sdk/inc/ntseapi.h $(BASEDIR)/public/sdk/inc/ntstatus.h \
+ $(BASEDIR)/public/sdk/inc/ntxcapi.h $(BASEDIR)/public/sdk/inc/poppack.h \
+ $(BASEDIR)/public/sdk/inc/ppcinst.h $(BASEDIR)/public/sdk/inc/pshpack1.h \
+ $(BASEDIR)/public/sdk/inc/pshpack4.h $(BASEDIR)/public/sdk/inc/windef.h \
+ $(BASEDIR)/public/sdk/inc/winerror.h $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/init.obj $(SNODVNBTOBJD)/init.obj $(VNBTSRC)/init.lst: \
+ $(VNBTSRC)/init.c ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h ../blt/dhcpinfo.h $(INC)/ctemacro.h \
+ $(INC)/debug.h $(INC)/hosts.h $(INC)/nbtinfo.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/ipinfo.h \
+ $(BASEDIR)/private/inc/nbtioctl.h $(BASEDIR)/private/inc/nettypes.h \
+ $(BASEDIR)/private/inc/packoff.h $(BASEDIR)/private/inc/packon.h \
+ $(BASEDIR)/private/inc/sockets/netinet/in.h $(BASEDIR)/private/inc/status.h \
+ $(BASEDIR)/private/inc/sys/snet/ip_proto.h $(BASEDIR)/private/inc/tdi.h \
+ $(BASEDIR)/private/inc/tdiinfo.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/nbtinfo.obj $(SNODVNBTOBJD)/nbtinfo.obj $(VNBTSRC)/nbtinfo.lst: \
+ $(VNBTSRC)/nbtinfo.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h ../blt/dhcpinfo.h $(INC)/ctemacro.h \
+ $(INC)/debug.h $(INC)/nbtinfo.h $(INC)/nbtnt.h $(INC)/nbtprocs.h \
+ $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h $(INC)/vxddebug.h \
+ $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h $(CHICAGO)/tcp/h/tdivxd.h \
+ $(BASEDIR)/private/inc/nbtioctl.h $(BASEDIR)/private/inc/nettypes.h \
+ $(BASEDIR)/private/inc/packoff.h $(BASEDIR)/private/inc/packon.h \
+ $(BASEDIR)/private/inc/sockets/netinet/in.h $(BASEDIR)/private/inc/status.h \
+ $(BASEDIR)/private/inc/sys/snet/ip_proto.h $(BASEDIR)/private/inc/tdi.h \
+ $(BASEDIR)/private/inc/tdikrnl.h $(BASEDIR)/private/inc/tdistat.h \
+ $(BASEDIR)/public/sdk/inc/alphaops.h $(BASEDIR)/public/sdk/inc/crt/ctype.h \
+ $(BASEDIR)/public/sdk/inc/crt/excpt.h $(BASEDIR)/public/sdk/inc/crt/limits.h \
+ $(BASEDIR)/public/sdk/inc/crt/stdarg.h $(BASEDIR)/public/sdk/inc/crt/stddef.h \
+ $(BASEDIR)/public/sdk/inc/crt/string.h $(BASEDIR)/public/sdk/inc/devioctl.h \
+ $(BASEDIR)/public/sdk/inc/lintfunc.hxx $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/netevent.h \
+ $(BASEDIR)/public/sdk/inc/nt.h $(BASEDIR)/public/sdk/inc/ntalpha.h \
+ $(BASEDIR)/public/sdk/inc/ntconfig.h $(BASEDIR)/public/sdk/inc/ntddtdi.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntppc.h $(BASEDIR)/public/sdk/inc/ntpsapi.h \
+ $(BASEDIR)/public/sdk/inc/ntregapi.h $(BASEDIR)/public/sdk/inc/ntrtl.h \
+ $(BASEDIR)/public/sdk/inc/ntseapi.h $(BASEDIR)/public/sdk/inc/ntstatus.h \
+ $(BASEDIR)/public/sdk/inc/ntxcapi.h $(BASEDIR)/public/sdk/inc/poppack.h \
+ $(BASEDIR)/public/sdk/inc/ppcinst.h $(BASEDIR)/public/sdk/inc/pshpack1.h \
+ $(BASEDIR)/public/sdk/inc/pshpack4.h $(BASEDIR)/public/sdk/inc/windef.h \
+ $(BASEDIR)/public/sdk/inc/winerror.h $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/ncb.obj $(SNODVNBTOBJD)/ncb.obj $(VNBTSRC)/ncb.lst: $(VNBTSRC)/ncb.c \
+ ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/tdiaddr.obj $(SNODVNBTOBJD)/tdiaddr.obj $(VNBTSRC)/tdiaddr.lst: \
+ $(VNBTSRC)/tdiaddr.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/tdicnct.obj $(SNODVNBTOBJD)/tdicnct.obj $(VNBTSRC)/tdicnct.lst: \
+ $(VNBTSRC)/tdicnct.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/tdihndlr.obj $(SNODVNBTOBJD)/tdihndlr.obj $(VNBTSRC)/tdihndlr.lst: \
+ $(VNBTSRC)/tdihndlr.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/tdiout.obj $(SNODVNBTOBJD)/tdiout.obj $(VNBTSRC)/tdiout.lst: \
+ $(VNBTSRC)/tdiout.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/timer.obj $(SNODVNBTOBJD)/timer.obj $(VNBTSRC)/timer.lst: \
+ $(VNBTSRC)/timer.c ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/util.obj $(SNODVNBTOBJD)/util.obj $(VNBTSRC)/util.lst: \
+ $(VNBTSRC)/util.c ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/vxddebug.obj $(SNODVNBTOBJD)/vxddebug.obj $(VNBTSRC)/vxddebug.lst: \
+ $(VNBTSRC)/vxddebug.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/vxdisol.obj $(SNODVNBTOBJD)/vxdisol.obj $(VNBTSRC)/vxdisol.lst: \
+ $(VNBTSRC)/vxdisol.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(SNOVNBTOBJD)/wfw.obj $(SNODVNBTOBJD)/wfw.obj $(VNBTSRC)/wfw.lst: $(VNBTSRC)/wfw.c \
+ ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h ../blt/dhcpinfo.h $(INC)/ctemacro.h \
+ $(INC)/debug.h $(INC)/nbtinfo.h $(INC)/nbtnt.h $(INC)/nbtprocs.h \
+ $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h $(INC)/vxddebug.h \
+ $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h $(CHICAGO)/tcp/h/tdivxd.h \
+ $(BASEDIR)/private/inc/ipinfo.h $(BASEDIR)/private/inc/llinfo.h \
+ $(BASEDIR)/private/inc/nbtioctl.h $(BASEDIR)/private/inc/nettypes.h \
+ $(BASEDIR)/private/inc/packoff.h $(BASEDIR)/private/inc/packon.h \
+ $(BASEDIR)/private/inc/sockets/netinet/in.h $(BASEDIR)/private/inc/status.h \
+ $(BASEDIR)/private/inc/sys/snet/ip_proto.h $(BASEDIR)/private/inc/tdi.h \
+ $(BASEDIR)/private/inc/tdiinfo.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/chic.obj $(CHIDVNBTOBJD)/chic.obj $(VNBTSRC)/chic.lst: \
+ $(VNBTSRC)/chic.c ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h ../blt/dhcpinfo.h $(INC)/ctemacro.h \
+ $(INC)/debug.h $(INC)/nbtinfo.h $(INC)/nbtnt.h $(INC)/nbtprocs.h \
+ $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h $(INC)/vxddebug.h \
+ $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h $(CHICAGO)/tcp/h/tdivxd.h \
+ $(BASEDIR)/private/inc/ipinfo.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdiinfo.h \
+ $(BASEDIR)/private/inc/tdikrnl.h $(BASEDIR)/private/inc/tdistat.h \
+ $(BASEDIR)/public/sdk/inc/alphaops.h $(BASEDIR)/public/sdk/inc/crt/ctype.h \
+ $(BASEDIR)/public/sdk/inc/crt/excpt.h $(BASEDIR)/public/sdk/inc/crt/limits.h \
+ $(BASEDIR)/public/sdk/inc/crt/stdarg.h $(BASEDIR)/public/sdk/inc/crt/stddef.h \
+ $(BASEDIR)/public/sdk/inc/crt/string.h $(BASEDIR)/public/sdk/inc/devioctl.h \
+ $(BASEDIR)/public/sdk/inc/lintfunc.hxx $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/netevent.h \
+ $(BASEDIR)/public/sdk/inc/nt.h $(BASEDIR)/public/sdk/inc/ntalpha.h \
+ $(BASEDIR)/public/sdk/inc/ntconfig.h $(BASEDIR)/public/sdk/inc/ntddtdi.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntppc.h $(BASEDIR)/public/sdk/inc/ntpsapi.h \
+ $(BASEDIR)/public/sdk/inc/ntregapi.h $(BASEDIR)/public/sdk/inc/ntrtl.h \
+ $(BASEDIR)/public/sdk/inc/ntseapi.h $(BASEDIR)/public/sdk/inc/ntstatus.h \
+ $(BASEDIR)/public/sdk/inc/ntxcapi.h $(BASEDIR)/public/sdk/inc/poppack.h \
+ $(BASEDIR)/public/sdk/inc/ppcinst.h $(BASEDIR)/public/sdk/inc/pshpack1.h \
+ $(BASEDIR)/public/sdk/inc/pshpack4.h $(BASEDIR)/public/sdk/inc/windef.h \
+ $(BASEDIR)/public/sdk/inc/winerror.h $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/fileio.obj $(CHIDVNBTOBJD)/fileio.obj $(VNBTSRC)/fileio.lst: \
+ $(VNBTSRC)/fileio.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/hosts.h \
+ $(INC)/nbtnt.h $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h \
+ $(INC)/types.h $(INC)/vxddebug.h $(INC)/vxdprocs.h \
+ $(CHICAGO)/tcp/h/oscfg.h $(CHICAGO)/tcp/h/tdivxd.h \
+ $(BASEDIR)/private/inc/nbtioctl.h $(BASEDIR)/private/inc/nettypes.h \
+ $(BASEDIR)/private/inc/packoff.h $(BASEDIR)/private/inc/packon.h \
+ $(BASEDIR)/private/inc/sockets/netinet/in.h $(BASEDIR)/private/inc/status.h \
+ $(BASEDIR)/private/inc/sys/snet/ip_proto.h $(BASEDIR)/private/inc/tdi.h \
+ $(BASEDIR)/private/inc/tdikrnl.h $(BASEDIR)/private/inc/tdistat.h \
+ $(BASEDIR)/public/sdk/inc/alphaops.h $(BASEDIR)/public/sdk/inc/crt/ctype.h \
+ $(BASEDIR)/public/sdk/inc/crt/excpt.h $(BASEDIR)/public/sdk/inc/crt/limits.h \
+ $(BASEDIR)/public/sdk/inc/crt/stdarg.h $(BASEDIR)/public/sdk/inc/crt/stddef.h \
+ $(BASEDIR)/public/sdk/inc/crt/string.h $(BASEDIR)/public/sdk/inc/devioctl.h \
+ $(BASEDIR)/public/sdk/inc/lintfunc.hxx $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/netevent.h \
+ $(BASEDIR)/public/sdk/inc/nt.h $(BASEDIR)/public/sdk/inc/ntalpha.h \
+ $(BASEDIR)/public/sdk/inc/ntconfig.h $(BASEDIR)/public/sdk/inc/ntddtdi.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntppc.h $(BASEDIR)/public/sdk/inc/ntpsapi.h \
+ $(BASEDIR)/public/sdk/inc/ntregapi.h $(BASEDIR)/public/sdk/inc/ntrtl.h \
+ $(BASEDIR)/public/sdk/inc/ntseapi.h $(BASEDIR)/public/sdk/inc/ntstatus.h \
+ $(BASEDIR)/public/sdk/inc/ntxcapi.h $(BASEDIR)/public/sdk/inc/poppack.h \
+ $(BASEDIR)/public/sdk/inc/ppcinst.h $(BASEDIR)/public/sdk/inc/pshpack1.h \
+ $(BASEDIR)/public/sdk/inc/pshpack4.h $(BASEDIR)/public/sdk/inc/windef.h \
+ $(BASEDIR)/public/sdk/inc/winerror.h $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/init.obj $(CHIDVNBTOBJD)/init.obj $(VNBTSRC)/init.lst: \
+ $(VNBTSRC)/init.c ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h ../blt/dhcpinfo.h $(INC)/ctemacro.h \
+ $(INC)/debug.h $(INC)/hosts.h $(INC)/nbtinfo.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/ipinfo.h \
+ $(BASEDIR)/private/inc/nbtioctl.h $(BASEDIR)/private/inc/nettypes.h \
+ $(BASEDIR)/private/inc/packoff.h $(BASEDIR)/private/inc/packon.h \
+ $(BASEDIR)/private/inc/sockets/netinet/in.h $(BASEDIR)/private/inc/status.h \
+ $(BASEDIR)/private/inc/sys/snet/ip_proto.h $(BASEDIR)/private/inc/tdi.h \
+ $(BASEDIR)/private/inc/tdiinfo.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/nbtinfo.obj $(CHIDVNBTOBJD)/nbtinfo.obj $(VNBTSRC)/nbtinfo.lst: \
+ $(VNBTSRC)/nbtinfo.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h ../blt/dhcpinfo.h $(INC)/ctemacro.h \
+ $(INC)/debug.h $(INC)/nbtinfo.h $(INC)/nbtnt.h $(INC)/nbtprocs.h \
+ $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h $(INC)/vxddebug.h \
+ $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h $(CHICAGO)/tcp/h/tdivxd.h \
+ $(BASEDIR)/private/inc/nbtioctl.h $(BASEDIR)/private/inc/nettypes.h \
+ $(BASEDIR)/private/inc/packoff.h $(BASEDIR)/private/inc/packon.h \
+ $(BASEDIR)/private/inc/sockets/netinet/in.h $(BASEDIR)/private/inc/status.h \
+ $(BASEDIR)/private/inc/sys/snet/ip_proto.h $(BASEDIR)/private/inc/tdi.h \
+ $(BASEDIR)/private/inc/tdikrnl.h $(BASEDIR)/private/inc/tdistat.h \
+ $(BASEDIR)/public/sdk/inc/alphaops.h $(BASEDIR)/public/sdk/inc/crt/ctype.h \
+ $(BASEDIR)/public/sdk/inc/crt/excpt.h $(BASEDIR)/public/sdk/inc/crt/limits.h \
+ $(BASEDIR)/public/sdk/inc/crt/stdarg.h $(BASEDIR)/public/sdk/inc/crt/stddef.h \
+ $(BASEDIR)/public/sdk/inc/crt/string.h $(BASEDIR)/public/sdk/inc/devioctl.h \
+ $(BASEDIR)/public/sdk/inc/lintfunc.hxx $(BASEDIR)/public/sdk/inc/mipsinst.h \
+ $(BASEDIR)/public/sdk/inc/nb30.h $(BASEDIR)/public/sdk/inc/netevent.h \
+ $(BASEDIR)/public/sdk/inc/nt.h $(BASEDIR)/public/sdk/inc/ntalpha.h \
+ $(BASEDIR)/public/sdk/inc/ntconfig.h $(BASEDIR)/public/sdk/inc/ntddtdi.h \
+ $(BASEDIR)/public/sdk/inc/ntdef.h $(BASEDIR)/public/sdk/inc/ntelfapi.h \
+ $(BASEDIR)/public/sdk/inc/ntexapi.h $(BASEDIR)/public/sdk/inc/nti386.h \
+ $(BASEDIR)/public/sdk/inc/ntimage.h $(BASEDIR)/public/sdk/inc/ntioapi.h \
+ $(BASEDIR)/public/sdk/inc/ntiolog.h $(BASEDIR)/public/sdk/inc/ntkeapi.h \
+ $(BASEDIR)/public/sdk/inc/ntldr.h $(BASEDIR)/public/sdk/inc/ntlpcapi.h \
+ $(BASEDIR)/public/sdk/inc/ntmips.h $(BASEDIR)/public/sdk/inc/ntmmapi.h \
+ $(BASEDIR)/public/sdk/inc/ntnls.h $(BASEDIR)/public/sdk/inc/ntobapi.h \
+ $(BASEDIR)/public/sdk/inc/ntppc.h $(BASEDIR)/public/sdk/inc/ntpsapi.h \
+ $(BASEDIR)/public/sdk/inc/ntregapi.h $(BASEDIR)/public/sdk/inc/ntrtl.h \
+ $(BASEDIR)/public/sdk/inc/ntseapi.h $(BASEDIR)/public/sdk/inc/ntstatus.h \
+ $(BASEDIR)/public/sdk/inc/ntxcapi.h $(BASEDIR)/public/sdk/inc/poppack.h \
+ $(BASEDIR)/public/sdk/inc/ppcinst.h $(BASEDIR)/public/sdk/inc/pshpack1.h \
+ $(BASEDIR)/public/sdk/inc/pshpack4.h $(BASEDIR)/public/sdk/inc/windef.h \
+ $(BASEDIR)/public/sdk/inc/winerror.h $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/ncb.obj $(CHIDVNBTOBJD)/ncb.obj $(VNBTSRC)/ncb.lst: $(VNBTSRC)/ncb.c \
+ ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/tdiaddr.obj $(CHIDVNBTOBJD)/tdiaddr.obj $(VNBTSRC)/tdiaddr.lst: \
+ $(VNBTSRC)/tdiaddr.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/tdicnct.obj $(CHIDVNBTOBJD)/tdicnct.obj $(VNBTSRC)/tdicnct.lst: \
+ $(VNBTSRC)/tdicnct.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/tdihndlr.obj $(CHIDVNBTOBJD)/tdihndlr.obj $(VNBTSRC)/tdihndlr.lst: \
+ $(VNBTSRC)/tdihndlr.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/tdiout.obj $(CHIDVNBTOBJD)/tdiout.obj $(VNBTSRC)/tdiout.lst: \
+ $(VNBTSRC)/tdiout.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/timer.obj $(CHIDVNBTOBJD)/timer.obj $(VNBTSRC)/timer.lst: \
+ $(VNBTSRC)/timer.c ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/util.obj $(CHIDVNBTOBJD)/util.obj $(VNBTSRC)/util.lst: \
+ $(VNBTSRC)/util.c ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/vxddebug.obj $(CHIDVNBTOBJD)/vxddebug.obj $(VNBTSRC)/vxddebug.lst: \
+ $(VNBTSRC)/vxddebug.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/vxdisol.obj $(CHIDVNBTOBJD)/vxdisol.obj $(VNBTSRC)/vxdisol.lst: \
+ $(VNBTSRC)/vxdisol.c ../$(INC)/alpha.h ../$(INC)/alpharef.h \
+ ../$(INC)/arc.h ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h $(INC)/ctemacro.h $(INC)/debug.h $(INC)/nbtnt.h \
+ $(INC)/nbtprocs.h $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h \
+ $(INC)/vxddebug.h $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h \
+ $(CHICAGO)/tcp/h/tdivxd.h $(BASEDIR)/private/inc/nbtioctl.h \
+ $(BASEDIR)/private/inc/nettypes.h $(BASEDIR)/private/inc/packoff.h \
+ $(BASEDIR)/private/inc/packon.h $(BASEDIR)/private/inc/sockets/netinet/in.h \
+ $(BASEDIR)/private/inc/status.h $(BASEDIR)/private/inc/sys/snet/ip_proto.h \
+ $(BASEDIR)/private/inc/tdi.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
+$(CHIVNBTOBJD)/wfw.obj $(CHIDVNBTOBJD)/wfw.obj $(VNBTSRC)/wfw.lst: $(VNBTSRC)/wfw.c \
+ ../$(INC)/alpha.h ../$(INC)/alpharef.h ../$(INC)/arc.h \
+ ../$(INC)/bugcodes.h ../$(INC)/cache.h ../$(INC)/cm.h \
+ ../$(INC)/cxport.h ../$(INC)/dbgk.h ../$(INC)/ex.h \
+ ../$(INC)/exboosts.h ../$(INC)/exlevels.h ../$(INC)/hal.h \
+ ../$(INC)/i386.h ../$(INC)/init.h ../$(INC)/io.h ../$(INC)/kd.h \
+ ../$(INC)/ke.h ../$(INC)/lfs.h ../$(INC)/lpc.h ../$(INC)/mips.h \
+ ../$(INC)/mm.h ../$(INC)/ntddk.h ../$(INC)/ntiologc.h \
+ ../$(INC)/ntmp.h ../$(INC)/ntos.h ../$(INC)/ntosdef.h ../$(INC)/ob.h \
+ ../$(INC)/ppc.h ../$(INC)/ps.h ../$(INC)/se.h ../$(INC)/updriver.h \
+ ../$(INC)/v86emul.h ../blt/dhcpinfo.h $(INC)/ctemacro.h \
+ $(INC)/debug.h $(INC)/nbtinfo.h $(INC)/nbtnt.h $(INC)/nbtprocs.h \
+ $(INC)/ntprocs.h $(INC)/timer.h $(INC)/types.h $(INC)/vxddebug.h \
+ $(INC)/vxdprocs.h $(CHICAGO)/tcp/h/oscfg.h $(CHICAGO)/tcp/h/tdivxd.h \
+ $(BASEDIR)/private/inc/ipinfo.h $(BASEDIR)/private/inc/llinfo.h \
+ $(BASEDIR)/private/inc/nbtioctl.h $(BASEDIR)/private/inc/nettypes.h \
+ $(BASEDIR)/private/inc/packoff.h $(BASEDIR)/private/inc/packon.h \
+ $(BASEDIR)/private/inc/sockets/netinet/in.h $(BASEDIR)/private/inc/status.h \
+ $(BASEDIR)/private/inc/sys/snet/ip_proto.h $(BASEDIR)/private/inc/tdi.h \
+ $(BASEDIR)/private/inc/tdiinfo.h $(BASEDIR)/private/inc/tdikrnl.h \
+ $(BASEDIR)/private/inc/tdistat.h $(BASEDIR)/public/sdk/inc/alphaops.h \
+ $(BASEDIR)/public/sdk/inc/crt/ctype.h $(BASEDIR)/public/sdk/inc/crt/excpt.h \
+ $(BASEDIR)/public/sdk/inc/crt/limits.h $(BASEDIR)/public/sdk/inc/crt/stdarg.h \
+ $(BASEDIR)/public/sdk/inc/crt/stddef.h $(BASEDIR)/public/sdk/inc/crt/string.h \
+ $(BASEDIR)/public/sdk/inc/devioctl.h $(BASEDIR)/public/sdk/inc/lintfunc.hxx \
+ $(BASEDIR)/public/sdk/inc/mipsinst.h $(BASEDIR)/public/sdk/inc/nb30.h \
+ $(BASEDIR)/public/sdk/inc/netevent.h $(BASEDIR)/public/sdk/inc/nt.h \
+ $(BASEDIR)/public/sdk/inc/ntalpha.h $(BASEDIR)/public/sdk/inc/ntconfig.h \
+ $(BASEDIR)/public/sdk/inc/ntddtdi.h $(BASEDIR)/public/sdk/inc/ntdef.h \
+ $(BASEDIR)/public/sdk/inc/ntelfapi.h $(BASEDIR)/public/sdk/inc/ntexapi.h \
+ $(BASEDIR)/public/sdk/inc/nti386.h $(BASEDIR)/public/sdk/inc/ntimage.h \
+ $(BASEDIR)/public/sdk/inc/ntioapi.h $(BASEDIR)/public/sdk/inc/ntiolog.h \
+ $(BASEDIR)/public/sdk/inc/ntkeapi.h $(BASEDIR)/public/sdk/inc/ntldr.h \
+ $(BASEDIR)/public/sdk/inc/ntlpcapi.h $(BASEDIR)/public/sdk/inc/ntmips.h \
+ $(BASEDIR)/public/sdk/inc/ntmmapi.h $(BASEDIR)/public/sdk/inc/ntnls.h \
+ $(BASEDIR)/public/sdk/inc/ntobapi.h $(BASEDIR)/public/sdk/inc/ntppc.h \
+ $(BASEDIR)/public/sdk/inc/ntpsapi.h $(BASEDIR)/public/sdk/inc/ntregapi.h \
+ $(BASEDIR)/public/sdk/inc/ntrtl.h $(BASEDIR)/public/sdk/inc/ntseapi.h \
+ $(BASEDIR)/public/sdk/inc/ntstatus.h $(BASEDIR)/public/sdk/inc/ntxcapi.h \
+ $(BASEDIR)/public/sdk/inc/poppack.h $(BASEDIR)/public/sdk/inc/ppcinst.h \
+ $(BASEDIR)/public/sdk/inc/pshpack1.h $(BASEDIR)/public/sdk/inc/pshpack4.h \
+ $(BASEDIR)/public/sdk/inc/windef.h $(BASEDIR)/public/sdk/inc/winerror.h \
+ $(BASEDIR)/public/sdk/inc/winnt.h
+
diff --git a/private/ntos/nbt/vxd/dns.c b/private/ntos/nbt/vxd/dns.c
new file mode 100644
index 000000000..f32bfccf4
--- /dev/null
+++ b/private/ntos/nbt/vxd/dns.c
@@ -0,0 +1,984 @@
+/*++
+
+Copyright (c) 1989-1996 Microsoft Corporation
+
+Module Name:
+
+ DNS.c
+
+Abstract:
+
+ VxD-specific DNS routines.
+
+ These routines try to resolve NetBIOS names using DNS.
+
+Author:
+
+ Earle R. Horton (ERH) 13-Feb-1996
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+
+//
+// function prototypes for completion routines that are local to this file
+//
+//----------------------------------------------------------------------------
+ VOID
+DnsCompletion(
+ PVOID pContext,
+ PVOID pContext2,
+ tTIMERQENTRY *pTimerQEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the timer code when the timer expires. It must
+ decide if another name query should be sent to the DNS server, and if not,
+ then it calls the client's completion routine (in completion2).
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+Notes:
+--*/
+
+{
+
+ NTSTATUS status;
+ tDGRAM_SEND_TRACKING *pTracker;
+ tDEVICECONTEXT *pDeviceContext;
+ CTELockHandle OldIrq;
+ COMPLETIONCLIENT pClientCompletion;
+ PCHAR pchDomainName;
+ USHORT Flags;
+ BOOL fOneMoreTry;
+ tDGRAM_SEND_TRACKING *pClientTracker;
+
+
+ KdPrint(("DnsCompletion entered\r\n"));
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pContext;
+ pDeviceContext = pTracker->pDeviceContext;
+
+
+ // if the client completion routine is not set anymore, then the
+ // timer has been cancelled and this routine should just clean up its
+ // buffers associated with the tracker (and return)
+ //
+ if (!pTimerQEntry)
+ {
+ // return the tracker block to its queue
+ LOCATION(0x52);
+ DereferenceTrackerNoLock((tDGRAM_SEND_TRACKING *)pContext);
+ return;
+ }
+
+
+ //
+ // to prevent a client from stopping the timer and deleting the
+ // pNameAddr, grab the lock and check if the timer has been stopped
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ if (pTimerQEntry->Flags & TIMER_RETIMED)
+ {
+ pTimerQEntry->Flags &= ~TIMER_RETIMED;
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ //
+ // if we are not bound to this card than use a very short timeout
+ //
+ if (!pTracker->pDeviceContext->pNameServerFileObject)
+ {
+ pTimerQEntry->DeltaTime = 10;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return;
+ }
+
+ if (!pTimerQEntry->ClientCompletion)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return;
+ }
+
+ pClientTracker = (tDGRAM_SEND_TRACKING *)pTimerQEntry->ClientContext;
+
+ //
+ // if the tracker has been cancelled, don't do any more queries
+ //
+ if (pClientTracker->Flags & TRACKER_CANCELLED)
+ {
+ pClientCompletion = pTimerQEntry->ClientCompletion;
+
+ // remove the link from the name table to this timer block
+ CHECK_PTR(((tNAMEADDR *)pTimerQEntry->pCacheEntry));
+
+ ((tNAMEADDR *)pTimerQEntry->pCacheEntry)->pTimer = NULL;
+
+ // to synch. with the StopTimer routine, Null the client
+ // completion routine so it gets called just once.
+ //
+ CHECK_PTR(pTimerQEntry);
+ pTimerQEntry->ClientCompletion = NULL;
+
+ //
+ // remove the name from the hash table, since it did not
+ // resolve via DNS either
+ //
+ CHECK_PTR(pTracker->pNameAddr);
+ pTracker->pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pTracker->pNameAddr->NameTypeState |= STATE_RELEASED;
+ pTracker->pNameAddr->pTimer = NULL;
+
+ //
+ // This call will remove the name from the PendingNameQueries List
+ //
+ NbtDereferenceName(pTracker->pNameAddr);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // there can be a list of trackers Q'd up on this name
+ // query, so we must complete all of them!
+ //
+ CompleteClientReq(pClientCompletion,
+ pClientTracker,
+ STATUS_CANCELLED);
+
+ // return the tracker block to its queue
+ LOCATION(0x51);
+ DereferenceTracker(pTracker);
+
+ KdPrint(("DNS resolution cancelled by client\r\n"));
+
+ return;
+
+ }
+
+ // If done with all the (3) retries with primary, try secondary DNS srvr
+ // If secondary not defined, or done with secondary as well, stop.
+ //
+
+ fOneMoreTry = TRUE;
+
+ if (!(--pTimerQEntry->Retries))
+ {
+ //
+ // if backup server is not defined, or if it is defined but we just
+ // finished trying backup server, go back and try primary server for
+ // "other domains"
+ // e.g. DNSDomains was defined as "msft.dom2.com,msft.dom3.com,msft.dom"
+ // We were pointing at msft.dom2.com. Now, we are done with that (and
+ // didn't get a response), so try msft.dom3.com
+ //
+ if ( ( !pDeviceContext->lDnsBackupServer ) ||
+ ( pDeviceContext->lDnsBackupServer == LOOP_BACK ) ||
+ ( pTracker->Flags & NBT_DNS_SERVER_BACKUP) )
+ {
+ //
+ // if we just got done trying primary domain name, try all the
+ // "other domains" specified
+ //
+ if (pTracker->pchDomainName == NbtConfig.pDomainName)
+ {
+ pTracker->pchDomainName = NbtConfig.pDNSDomains;
+ if ( pTracker->pchDomainName )
+ {
+ pTracker->Flags &= ~NBT_DNS_SERVER_BACKUP;
+ pTracker->Flags |= NBT_DNS_SERVER;
+ pTimerQEntry->Retries = NbtConfig.uNumRetries;
+ }
+ else
+ {
+ fOneMoreTry = FALSE;
+ }
+ }
+
+ //
+ // if we had already started on "other domains", advance to the
+ // next domain within "other domains"
+ //
+ else
+ {
+ pchDomainName = pTracker->pchDomainName;
+ while( *pchDomainName != ',' && // dom names separated by comma
+ *pchDomainName != ' ' && // or space
+ *pchDomainName != '\0' )
+ pchDomainName++;
+
+ if ( *pchDomainName == '\0' )
+ fOneMoreTry = FALSE;
+ else
+ {
+ pchDomainName++;
+ pTracker->pchDomainName = pchDomainName;
+ pTracker->Flags &= ~NBT_DNS_SERVER_BACKUP;
+ pTracker->Flags |= NBT_DNS_SERVER;
+ pTimerQEntry->Retries = NbtConfig.uNumRetries;
+ }
+ }
+ }
+
+ // ok, prepare to try the backup server
+ else
+ {
+ pTimerQEntry->Retries = NbtConfig.uNumRetries;
+
+ pTracker->Flags &= ~NBT_DNS_SERVER;
+ pTracker->Flags |= NBT_DNS_SERVER_BACKUP;
+ }
+ }
+
+ // we aren't done yet: send one more query and restart the timer
+ if (fOneMoreTry)
+ {
+ pTracker->RefCount++;
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ status = UdpSendNSBcast(pTracker->pNameAddr,
+ NbtConfig.pScope,
+ pTracker,
+ NULL,NULL,NULL,
+ 0,0,
+ eDNS_NAME_QUERY,
+ TRUE);
+
+ DereferenceTracker(pTracker);
+
+ pTimerQEntry->Flags |= TIMER_RESTART;
+
+ KdPrint(("One more DNS query sent out\r\n"));
+ }
+
+ // yup, all done: didn't find the name! give client above the bad news
+ else
+ {
+ tDGRAM_SEND_TRACKING *pClientTracker;
+
+
+ pClientTracker = (tDGRAM_SEND_TRACKING *)pTimerQEntry->ClientContext;
+
+ pClientCompletion = pTimerQEntry->ClientCompletion;
+
+ // remove the link from the name table to this timer block
+ CHECK_PTR(((tNAMEADDR *)pTimerQEntry->pCacheEntry));
+
+ ((tNAMEADDR *)pTimerQEntry->pCacheEntry)->pTimer = NULL;
+
+ // to synch. with the StopTimer routine, Null the client
+ // completion routine so it gets called just once.
+ //
+ CHECK_PTR(pTimerQEntry);
+ pTimerQEntry->ClientCompletion = NULL;
+
+ //
+ // remove the name from the hash table, since it did not
+ // resolve via DNS either
+ //
+ CHECK_PTR(pTracker->pNameAddr);
+ pTracker->pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
+ pTracker->pNameAddr->NameTypeState |= STATE_RELEASED;
+ pTracker->pNameAddr->pTimer = NULL;
+
+ //
+ // This call will remove the name from the PendingNameQueries List
+ //
+ NbtDereferenceName(pTracker->pNameAddr);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ // there can be a list of trackers Q'd up on this name
+ // query, so we must complete all of them!
+ //
+ CompleteClientReq(pClientCompletion,
+ pClientTracker,
+ STATUS_TIMEOUT);
+
+ // return the tracker block to its queue
+ LOCATION(0x51);
+ DereferenceTracker(pTracker);
+
+ KdPrint(("DNS resolution failed: told client\r\n"));
+ }
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+DoDnsResolve (
+ IN NBT_WORK_ITEM_CONTEXT *Context
+ )
+/*++
+
+Routine Description:
+
+ This function is used to allow NBT to query DNS. This is very much like
+ the name query sent out to WINS server or broadcast. Response from the
+ DNS server, if any, is handled by the QueryFromNet() routine.
+
+Arguments:
+
+ *Context (NBT_WORK_ITEM_CONTEXT)
+
+Return Value:
+
+ STATUS_PENDING (unless something goes wrong)
+
+Notes:
+--*/
+
+{
+
+ tDGRAM_SEND_TRACKING *pTracker;
+ tDEVICECONTEXT *pDeviceContext;
+ ULONG Timeout;
+ USHORT Retries;
+ NTSTATUS status;
+ PVOID pClientCompletion;
+ PVOID pCompletionRoutine;
+ PVOID pClientContext;
+
+
+
+ KdPrint(("DoDnsResolve entered\r\n"));
+
+ pTracker = Context->pTracker;
+
+ pDeviceContext = pTracker->pDeviceContext;
+
+ //
+ // If the primary DNS server is not defined, just return error.
+ if ( (!pDeviceContext->lDnsServerAddress) ||
+ ( pDeviceContext->lDnsServerAddress == LOOP_BACK) )
+ {
+ return( NRC_CMDTMO );
+ }
+
+ pTracker->Flags &= ~(NBT_BROADCAST|NBT_NAME_SERVER|NBT_NAME_SERVER_BACKUP);
+ pTracker->Flags |= NBT_DNS_SERVER;
+
+ pClientContext = Context->pClientContext;
+ pClientCompletion = Context->ClientCompletion;
+ pCompletionRoutine = DnsCompletion;
+
+ //
+ // free that memory now
+ //
+ CTEMemFree(Context);
+
+ //
+ // Put on the pending name queries list again so that when the query
+ // response comes in from DNS we can find the pNameAddr record.
+ //
+ ExInterlockedInsertTailList(&NbtConfig.PendingNameQueries,
+ &pTracker->pNameAddr->Linkage,
+ &NbtConfig.JointLock.SpinLock);
+
+ Timeout = (ULONG)pNbtGlobConfig->uRetryTimeout;
+ Retries = pNbtGlobConfig->uNumRetries;
+
+ pTracker->RefCount++;
+
+ //
+ // first time, we want to try the primary domain name
+ //
+ pTracker->pchDomainName = NbtConfig.pDomainName;
+
+ status = UdpSendNSBcast(pTracker->pNameAddr,
+ NbtConfig.pScope,
+ pTracker,
+ pCompletionRoutine,
+ pClientContext,
+ pClientCompletion,
+ Retries,
+ Timeout,
+ eDNS_NAME_QUERY,
+ TRUE);
+
+ DereferenceTracker(pTracker);
+
+ KdPrint(("Leaving DoDnsResolve\r\n"));
+
+ return( status );
+
+
+}
+
+//----------------------------------------------------------------------------
+ PCHAR
+DnsStoreName
+(
+ OUT PCHAR pDest,
+ IN PCHAR pName,
+ IN PCHAR pDomainName,
+ IN enum eNSTYPE eNsType
+ )
+/*++
+
+Routine Description:
+
+ This routine copies the netbios name (and appends the scope on the
+ end) in the DNS namequery packet
+
+Arguments:
+
+
+Return Value:
+
+ the address of the next byte in the destination after the the name
+ has been copied
+
+--*/
+{
+ LONG i;
+ LONG count;
+ PCHAR pStarting;
+ PCHAR pSrc;
+ LONG DomNameSize;
+ LONG OneMoreSubfield;
+
+ LONG lMaxCount;
+ CHAR cTerminator;
+
+ if (eNsType == eDIRECT_DNS_NAME_QUERY)
+ {
+ lMaxCount = 255;
+ cTerminator = 0;
+ }
+ else
+ {
+ lMaxCount = NETBIOS_NAME_SIZE-1;
+ cTerminator = 0x20;
+ }
+
+
+ pStarting = pDest++;
+ count = 0;
+ //
+ // copy until we reach the space padding
+ //
+ while ( ( count < lMaxCount ) && (*pName != cTerminator) )
+ {
+ *pDest++ = *pName++;
+ count++;
+ }
+
+ *pStarting = (CHAR)count;
+
+ //
+ // check if domain name exists. koti.microsoft.com will be represented
+ // as 4KOTI9microsoft3com0 (where nos. => no. of bytes of subfield)
+ //
+ pSrc = pDomainName;
+ if (pSrc && pSrc[0] != '\0')
+ {
+ OneMoreSubfield = 1;
+
+ while( OneMoreSubfield )
+ {
+ count = 0;
+ pStarting = pDest++;
+ //
+ // remember, the domain name we receive can also be a set of "other
+ // domains" to try in the form "msft.dom2.com,msft.dom3.com"
+ //
+ while ( *pSrc != '.' && *pSrc != '\0' && *pSrc != ',')
+ {
+ *pDest++ = *pSrc++;
+ count++;
+ }
+ *pStarting = (CHAR)count;
+
+ if (*pSrc == '\0' || *pSrc == ',')
+ OneMoreSubfield = 0;
+ else
+ pSrc++;
+ }
+ }
+
+ *pDest++ = 0;
+
+
+ // return the address of the next byte of the destination
+ return(pDest);
+}
+
+
+
+
+//----------------------------------------------------------------------------
+ VOID
+DnsExtractName(
+ IN PCHAR pNameHdr,
+ IN LONG NumBytes,
+ OUT PCHAR pName,
+ OUT PULONG pNameSize
+ )
+/*++
+
+Routine Description:
+
+ This routine extracts the name from the packet and then appends the scope
+ onto the end of the name to make a full name.
+
+Arguments:
+ NumBytes - the total number of bytes in the message - may include
+ more than just the name itself
+
+Return Value:
+
+
+--*/
+{
+
+
+ LONG i;
+ int iIndex;
+ LONG lValue;
+ ULONG UNALIGNED *pHdr;
+ PCHAR pSavName;
+ ULONG Len;
+
+
+ KdPrint(("DnsExtractName entered\r\n"));
+
+ //
+ // how long is the name we received
+ //
+ Len = (ULONG)((UCHAR)*pNameHdr);
+
+ ++pNameHdr; // to increment past the length byte
+
+ pSavName = pName;
+
+ // copy the name (no domain) as given by DNS server (i.e., just copy
+ // foobar when DNS returned foobar.microsoft.com in the response
+ // (this is likely to be less than the usualy 16 byte len)
+ //
+ for (i=0; i < Len ;i++ )
+ {
+ *pName = *pNameHdr;
+ pNameHdr++;
+ if (i < NETBIOS_NAME_SIZE)
+ {
+ pName++;
+ }
+ }
+
+ //
+ // now, make it look like NBNS responded, by adding the 0x20 pad
+ //
+ for (i=Len; i<NETBIOS_NAME_SIZE; i++)
+ {
+ *pName++ = 0x20;
+ }
+
+ //
+ // convert all chars to uppercase since all our names are in uppercase!
+ //
+ for (i=0; i<NETBIOS_NAME_SIZE; i++)
+ {
+ if (*pSavName >= 'a' && *pSavName <= 'z')
+ *pSavName = *pSavName - ('a'-'A');
+
+ pSavName++;
+ }
+
+ //
+ // at this point we are pointing to the '.' after foobar. Find the
+ // length of the entire name
+ //
+ while ( (*pNameHdr != '\0') && (Len < NumBytes) )
+ {
+ pNameHdr++;
+ Len++;
+ }
+
+ Len++; // to account for the trailing 0
+
+ *pNameSize = Len;
+
+ KdPrint(("Leaving DnsExtractName\r\n"));
+
+ return;
+}
+
+
+//----------------------------------------------------------------------------
+ ULONG
+domnamelen(
+ IN PCHAR pDomainName
+ )
+/*++
+
+Routine Description:
+
+ This routine determines the length of the domainname. This is basically
+ strlen, except that the DNSDomain field is stored as a bunch of
+ domain names separated by commas, so we treat '\0' as well as ',' as
+ string terminators for this function.
+
+Arguments:
+
+
+Return Value:
+
+ length of the domain name
+
+--*/
+{
+
+ ULONG ulDomnameLen=0;
+
+ if (pDomainName)
+ {
+ while(*pDomainName != '\0' && *pDomainName != ',')
+ {
+ pDomainName++;
+ ulDomnameLen++;
+ }
+ }
+
+ return( ulDomnameLen );
+}
+
+//----------------------------------------------------------------------------
+ VOID
+ProcessDnsResponse(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN USHORT OpCodeFlags
+ )
+/*++
+
+Routine Description:
+
+ This function sets the state of the name being resolved appropriately
+ depending on whether DNS sends a positive or a negative response to our
+ query; calls the client completion routine and stops any more DNS queries
+ from going.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or STATUS_UNSUCCESSFUL
+
+--*/
+{
+
+
+ NTSTATUS status;
+ tDNS_QUERYRESP UNALIGNED *pQuery;
+ tNAMEADDR *pResp;
+ tTIMERQENTRY *pTimer;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+ PTRANSPORT_ADDRESS pSourceAddress;
+ ULONG SrcAddress;
+ CTELockHandle OldIrq1;
+ LONG lNameSize;
+ LONG lTraversedSoFar=0;
+ CHAR pName[NETBIOS_NAME_SIZE];
+ CHAR pJunkBuf[NETBIOS_NAME_SIZE];
+ PUCHAR pScope;
+ PUCHAR pchQry;
+
+
+
+ KdPrint(("ProcessDnsResponse entered\r\n"));
+
+
+ // make sure this is a response
+
+ if ( !(OpCodeFlags & OP_RESPONSE) )
+ {
+ CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponse: Bad OpCodeFlags\r\n"));
+
+ return;
+ }
+
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
+ SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
+
+ // get the name out of the network pdu and pass to routine to check
+ // local table
+ DnsExtractName( (PCHAR)&pNameHdr->NameRR.NameLength,
+ lNumBytes,
+ pName,
+ &lNameSize
+ );
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ //
+ // we chopped off 16th byte while sending a query, so compare only first
+ // 15 characters for a match
+ //
+ status = FindOnPendingList(pName,pNameHdr,FALSE,NETBIOS_NAME_SIZE-1,&pResp);
+
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // The name is not there in the remote name table. Nothing
+ // more to do. Just return.
+ //
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponse: name not found\r\n"));
+
+ return;
+ }
+
+ //
+ // If the response we received doesn't resolve the name, we silently return,
+ // but make sure reties is set to 1 so that when timer fires again, we don't
+ // send another name query to the same server but instead timeout the
+ // attempt on this server
+ //
+ if ((pTimer = pResp->pTimer))
+ {
+ pTimer->Retries = 1;
+ }
+
+
+ //
+ // check the pdu size for errors
+ //
+ if (lNumBytes < DNS_MINIMUM_QUERYRESPONSE)
+ {
+ CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponse: Bad lNumBytes\r\n"));
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ return;
+ }
+
+//
+// BUGBUG: should we require authoritative responses from DNS servers?
+//
+
+ //
+ // if it's a negative response, quit now!
+ //
+ if (IS_NEG_RESPONSE(OpCodeFlags))
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return;
+ }
+
+ //
+ // if there is no answer section, return!
+ //
+ if ( !pNameHdr->AnCount )
+ {
+ CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponse: No answer section\r\n"));
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return;
+ }
+
+ //
+ // lNameSize is the length of the entire name, excluding the length byte
+ // for the first label (including length bytes of subsequent labels) and
+ // including the trailing 0 (tNAMEHDR struc takes care for 1st byte)
+ //
+ pchQry = (PUCHAR)&pNameHdr->NameRR.NetBiosName[lNameSize];
+
+ lTraversedSoFar += lNameSize;
+
+ //
+ // if the Question section is returned with the response then we have
+ // a little more work to do! In this case, pQuery is pointing at the
+ // beginning of the QTYPE field (end of the QNAME)
+ //
+ if ( pNameHdr->QdCount )
+ {
+ pchQry += sizeof(tQUESTIONMODS);
+ lTraversedSoFar += sizeof(tQUESTIONMODS);
+
+ // most common case: 1st byte will be 0xC0, which means next byte points
+ // to the actual name. We don't care about the name, so we skip over
+ // both the bytes
+ //
+ if ( (*pchQry) == PTR_TO_NAME )
+ {
+ pchQry += sizeof(tDNS_LABEL);
+ lTraversedSoFar += sizeof(tDNS_LABEL);
+ }
+
+ //
+ // if some implementation doesn't optimize and copies the whole name
+ // again, skip over the length of the name
+ //
+ else
+ {
+ pchQry += (lNameSize+1); // +1 because of the 1st length byte!
+ lTraversedSoFar += (lNameSize+1);
+ }
+ }
+
+ pQuery = (tDNS_QUERYRESP *)pchQry;
+
+ //
+ // if this rr is telling us about canonical name, skip over it and go to
+ // where the ipaddr is
+ //
+ if (ntohs(pQuery->RrType) == DNS_CNAME)
+ {
+ //
+ // since this is CNAME, there is no ipaddr. Instead, the data is the
+ // canonical name whose length we are adding, and subtract ipaddr's len
+ //
+ pchQry += (sizeof(tDNS_QUERYRESP) - sizeof(ULONG));
+ pchQry += ntohs(pQuery->Length);
+ lTraversedSoFar += ntohs(pQuery->Length) + sizeof(tDNS_QUERYRESP) - sizeof(ULONG);
+
+ ASSERT(lNumBytes > lTraversedSoFar);
+
+ // most common case: 1st byte will be 0xC0, which means next byte points
+ // to the actual name. We don't care about the name, so we skip over
+ // both the bytes
+ //
+ if ( (*pchQry) == PTR_TO_NAME )
+ {
+ pchQry += sizeof(tDNS_LABEL);
+ lTraversedSoFar += sizeof(tDNS_LABEL);
+ }
+
+ //
+ // if some implementation doesn't optimize and copies the whole name
+ // again, skip over the length of the name
+ //
+ else
+ {
+ // we have already taken the name out. we are calling this routine
+ // just to see how big the canonical name is (i.e.lNameSize), to skip
+ // past it
+ //
+ DnsExtractName( pchQry,
+ lNumBytes-lTraversedSoFar,
+ pJunkBuf,
+ &lNameSize
+ );
+
+ //
+ // lNameSize is the length of the entire name, excluding the length byte
+ // for the first label (including length bytes of subsequent labels) and
+ // including the trailing 0 (tNAMEHDR struc takes care for 1st byte)
+ //
+ pchQry += lNameSize+1; // +1 for the length byte of first label
+
+ }
+
+ pQuery = (tDNS_QUERYRESP *)pchQry;
+ }
+
+
+ // if we came this far, it's a positive response. stop the timer and do
+ // the needful..
+
+ // remove any timer block and call the completion routine
+ if (pTimer)
+ {
+ USHORT Flags;
+ tDGRAM_SEND_TRACKING *pTracker;
+
+ pTracker = (tDGRAM_SEND_TRACKING *)pTimer->Context;
+
+ //
+ // this routine puts the timer block back on the timer Q, and
+ // handles race conditions to cancel the timer when the timer
+ // is expiring.
+ status = StopTimer(pTimer,&pClientCompletion,&Context);
+
+ //
+ // Synchronize with DnsCompletion
+ //
+ if (pClientCompletion)
+ {
+ CHECK_PTR(pResp);
+ pResp->pTimer = NULL;
+
+ //
+ // Remove from the PendingNameQueries List
+ //
+ RemoveEntryList(&pResp->Linkage);
+ InitializeListHead(&pResp->Linkage);
+
+ KdPrint(("ProcessDnsResponse: positive DNS response received\r\n"));
+
+ if (pResp->NameTypeState & STATE_RESOLVING)
+ {
+ pResp->NameTypeState &= ~NAME_STATE_MASK;
+ pResp->NameTypeState |= STATE_RESOLVED;
+
+ pResp->IpAddress = ntohl(pQuery->IpAddress);
+
+ pResp->AdapterMask = (CTEULONGLONG)-1;
+ status = AddRecordToHashTable(pResp,NbtConfig.pScope);
+
+ if (!NT_SUCCESS(status))
+ {
+ //
+ // the name must already be in the hash table,
+ // so dereference it to remove it
+ //
+ NbtDereferenceName(pResp);
+ }
+
+ IncrementNameStats(NAME_QUERY_SUCCESS, TRUE);
+ }
+
+ status = STATUS_SUCCESS;
+
+ //
+ // Set the backup name server to be the main name server
+ // since we got a response from it.
+ //
+ if ( SrcAddress == pDeviceContext->lDnsBackupServer )
+ {
+ pDeviceContext->lDnsBackupServer =
+ pDeviceContext->lDnsServerAddress;
+
+ pDeviceContext->lDnsServerAddress = SrcAddress;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ // the completion routine has not run yet, so run it
+ (void) CTEQueueForNonDispProcessing(
+ (tDGRAM_SEND_TRACKING *)Context,
+ (PVOID)status,
+ pClientCompletion,
+ DelayedSessEstablish,
+ pDeviceContext);
+ }
+
+ else
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ }
+
+ return;
+
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+
+ KdPrint(("Leaving ProcessDnsResponse\r\n"));
+
+ return;
+
+}
diff --git a/private/ntos/nbt/vxd/fileio.c b/private/ntos/nbt/vxd/fileio.c
new file mode 100644
index 000000000..b319ce290
--- /dev/null
+++ b/private/ntos/nbt/vxd/fileio.c
@@ -0,0 +1,476 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fileio.c
+
+Abstract:
+
+ This source implements a stdio-like facility.
+
+Author:
+
+ Eric Chin (ericc) April 28, 1992
+ John Ludeman (johnl) Oct 8, 1993 - Rewrote for Vxd
+
+Revision History:
+
+--*/
+
+#include <nbtprocs.h>
+#include "hosts.h"
+
+//
+// The maximum line length for a file in the lmhosts file is 256 bytes for
+// the Vxd
+//
+#define MAX_LMHOSTS_LINE 256
+
+//
+// The number of bytes we buffer on each read
+//
+#define LMHOSTS_READ_BUFF_SIZE 256
+
+UCHAR GetNextChar( PLM_FILE pFile ) ;
+
+VOID RestoreOldData( PLM_FILE pFile );
+
+BackupCurrentData( PLM_FILE pFile );
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, LmCloseFile)
+#pragma CTEMakePageable(PAGE, LmFgets)
+#pragma CTEMakePageable(PAGE, GetNextChar)
+#pragma CTEMakePageable(PAGE, LmOpenFile)
+#pragma CTEMakePageable(PAGE, BackupCurrentData)
+#pragma CTEMakePageable(PAGE, RestoreOldData)
+#endif
+
+#ifdef CHICAGO
+//
+// In case of chicago, use only linear addresses (Allocate_Global_V86_Data_Area
+// call is available only at init time, not if vnbt is load dynamically!)
+//
+#define pMappedFileBuff pFileBuff
+#define pMappedFilePath pFilePath
+
+#else
+//
+// In case of snowball, this is the address of the V86 mapped memory for
+// the file read buffer and lmhosts file path
+//
+PVOID pMappedFileBuff = NULL ;
+PVOID pMappedFilePath = NULL ;
+#endif
+
+//
+// Linear address for file buffer and path (accessible from Vxd)
+//
+PUCHAR pFileBuff = NULL ;
+PUCHAR pFilePath = NULL ;
+
+
+/*******************************************************************
+
+ NAME: VxdInitLmHostsSupport
+
+ SYNOPSIS: This function just allocates memory to read the contents
+ of file into.
+ (trying to minimize on changes to snowball side of code
+ whic has already shipped: that's why this function!)
+
+ ENTRY: pchLmHostPath - path to lmhosts file (not used here)
+ ulPathSize - size, in chars, of the path
+
+ RETURNS: TRUE if it works, FALSE if it doesn't.
+ COMMENTS: This is Chicago version of the function. Snowball's
+ version is in vxdfile.asm
+
+ HISTORY:
+ Koti Oct 10, 94
+
+********************************************************************/
+
+#ifdef CHICAGO
+BOOL
+VxdInitLmHostsSupport( PUCHAR pchLmHostPath, USHORT ulPathSize )
+{
+
+ USHORT Size;
+
+ Size = ulPathSize + LMHOSTS_READ_BUFF_SIZE;
+
+ pFileBuff = CTEAllocInitMem( Size );
+ if (pFileBuff == NULL)
+ {
+ DbgPrint("VxdInitLmHostsSupport: failed to allocate memory") ;
+ return( FALSE );
+ }
+
+ pFilePath = pFileBuff + LMHOSTS_READ_BUFF_SIZE;
+
+ return( TRUE );
+
+}
+
+#endif
+//----------------------------------------------------------------------------
+
+NTSTATUS
+LmCloseFile (
+ IN PLM_FILE pfile
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes a file opened via LmOpenFile(), and frees its
+ LM_FILE object.
+
+Arguments:
+
+ pfile - pointer to the LM_FILE object
+
+Return Value:
+
+ An NTSTATUS value.
+
+--*/
+
+
+{
+ CTEPagedCode();
+
+ CDbgPrint(DBGFLAG_LMHOST, "LmCloseFile entered\r\n") ;
+ CTEFreeMem( pfile->f_linebuffer );
+
+ VxdFileClose( pfile->f_handle ) ;
+
+ CTEFreeMem(pfile);
+
+ CDbgPrint(DBGFLAG_LMHOST, "LmCloseFile leaving\r\n") ;
+ return STATUS_SUCCESS ;
+
+} // LmCloseFile
+
+
+
+//----------------------------------------------------------------------------
+
+PUCHAR
+LmFgets (
+ IN PLM_FILE pfile,
+ OUT int *nbytes
+ )
+
+/*++
+
+Routine Description:
+
+ This function is vaguely similar to fgets(3).
+
+ Starting at the current seek position, it reads through a newline
+ character, or the end of the file. If a newline is encountered, it
+ is replaced with a NULL character.
+
+Arguments:
+
+ pfile - file to read from
+ nbytes - the number of characters read, excluding the NULL character
+
+Return Value:
+
+ A pointer to the beginning of the line, or NULL if we are at or past
+ the end of the file.
+
+--*/
+{
+ ULONG cbLine = 0 ;
+ UCHAR ch ;
+ BOOL fDone = FALSE ;
+ BOOL fEOL = FALSE ;
+
+
+ CTEPagedCode();
+
+ while ( TRUE )
+ {
+ switch ( ch = GetNextChar( pfile ))
+ {
+ case '\n': // End of line
+ if ( !cbLine ) // If it's just a '\n' by itself, ignore it
+ continue ;
+ //
+ // Fall through
+ //
+
+ case '\0': // End of file
+ pfile->f_linebuffer[cbLine] = '\0' ;
+ fDone = TRUE ;
+ fEOL = TRUE ;
+ break ;
+
+ case '\r': // Ignore
+ continue ;
+
+ default:
+ pfile->f_linebuffer[cbLine] = ch ;
+ if ( cbLine == (MAX_LMHOSTS_LINE-1) )
+ {
+ pfile->f_linebuffer[cbLine--] = '\0' ;
+ fDone = TRUE ;
+ }
+ break ;
+ }
+
+ if ( fDone )
+ break ;
+
+ cbLine++ ;
+ }
+
+ //
+ // Scan till the end of this line
+ //
+ if ( !fEOL )
+ {
+ while ( (ch = GetNextChar(pfile)) && ch != '\n' )
+ ;
+ }
+
+ if ( cbLine )
+ {
+ (pfile->f_lineno)++ ;
+ *nbytes = cbLine ;
+
+ CDbgPrint( DBGFLAG_LMHOST, "LmFgets returning \"") ;
+ CDbgPrint( DBGFLAG_LMHOST, pfile->f_linebuffer ) ;
+ CDbgPrint( DBGFLAG_LMHOST, "\", nbytes = 0x") ;
+ CDbgPrintNum( DBGFLAG_LMHOST, *nbytes ) ;
+ CDbgPrint( DBGFLAG_LMHOST, "\r\n") ;
+
+ return pfile->f_linebuffer ;
+ }
+
+ return NULL ;
+}
+
+/*******************************************************************
+
+ NAME: GetNextChar
+
+ SYNOPSIS: Gets the next character from the file or the line buffer
+
+ ENTRY: pFile - File we are operating on
+
+ RETURNS: Next character or '\0' if at the end of file (or there is an
+ embedded '\0' in the file).
+
+ NOTES:
+
+********************************************************************/
+
+UCHAR GetNextChar( PLM_FILE pFile )
+{
+ ULONG BytesRead ;
+
+ CTEPagedCode();
+
+ if ( pFile->f_CurPos < pFile->f_EndOfData )
+ return pFile->f_buffer[pFile->f_CurPos++] ;
+
+ if ( pFile->f_EOF )
+ return '\0' ;
+
+ //
+ // We've reached the end of the buffer, get more data
+ //
+ BytesRead = VxdFileRead( pFile->f_handle,
+ LMHOSTS_READ_BUFF_SIZE,
+ pMappedFileBuff ) ;
+ pFile->f_CurPos = 0 ;
+ if ( BytesRead < LMHOSTS_READ_BUFF_SIZE )
+ pFile->f_EOF = TRUE ;
+
+ //
+ // If haven't hit the end of the file, return the next character
+ //
+ if ( (pFile->f_EndOfData = BytesRead) )
+ return pFile->f_buffer[pFile->f_CurPos++] ;
+
+ return '\0' ;
+}
+
+
+
+//----------------------------------------------------------------------------
+
+PLM_FILE
+LmOpenFile (
+ IN PUCHAR path
+ )
+
+/*++
+
+Routine Description:
+
+ This function opens a file for use by LmFgets().
+
+Arguments:
+
+ path - a fully specified, complete path to the file.
+
+Return Value:
+
+ A pointer to an LM_FILE object, or NULL if unsuccessful.
+
+Notes:
+
+ The first time through, we map the lmhosts memory to vm memory and
+ allocate a read buffer and map that to VM memory. Note that this means
+ the path must not change and this routine is not reentrant!!
+
+ The reason for this is because the mapping is an expensive operation
+ (and there isn't a way to unmap when using Map_Lin_To_VM_Addr).
+
+--*/
+
+
+{
+ HANDLE handle;
+ PLM_FILE pfile;
+ PCHAR pLineBuff = CTEAllocMem( MAX_LMHOSTS_LINE ) ;
+ static int fInRoutine = 0 ;
+
+ CTEPagedCode();
+
+
+ if (fInRoutine++)
+ {
+ CDbgPrint( DBGFLAG_LMHOST, "exiting LmOpenFile: not reentrant!\r\n") ;
+ goto ErrorExit; // We're not reentrant
+ }
+
+ CDbgPrint( DBGFLAG_LMHOST, "LmOpenFile entered\r\n") ;
+
+ strcpy( pFilePath, path ) ;
+
+ if ( !pLineBuff || !pFileBuff )
+ goto ErrorExit ;
+
+ handle = (HANDLE) VxdFileOpen( pMappedFilePath ) ;
+
+ if ( handle == NULL )
+ {
+ goto ErrorExit ;
+ }
+
+ pfile = (PLM_FILE) CTEAllocMem( sizeof(LM_FILE) );
+
+ if (!pfile)
+ {
+ VxdFileClose( handle ) ;
+ goto ErrorExit ;
+ }
+
+ pfile->f_handle = handle;
+ pfile->f_lineno = 0;
+ pfile->f_buffer = pFileBuff ;
+ pfile->f_linebuffer = pLineBuff ;
+ pfile->f_EndOfData = 0 ;
+ pfile->f_CurPos = 0 ;
+ pfile->f_EOF = FALSE ;
+
+ CDbgPrint( DBGFLAG_LMHOST, "LmOpenFile returning\r\n") ;
+
+ fInRoutine-- ;
+
+ return pfile ;
+
+ErrorExit:
+
+ fInRoutine--;
+
+ if ( pLineBuff )
+ CTEFreeMem( pLineBuff ) ;
+
+ return NULL ;
+
+} // LmOpenFile
+
+
+//----------------------------------------------------------------------------
+
+BOOL
+BackupCurrentData( PLM_FILE pFile )
+
+/*++
+
+Routine Description:
+
+ This function backs up all the data from lmhosts file into another buffer
+ (which is allocated).
+ This function is called before opening the next file that we encountered
+ via #INCLUDE. Since the same buffer is used to store the VxdReadFile data,
+ we need to save this data.
+
+Arguments:
+
+ pFile - LMfile pointer
+
+Return Value:
+
+ TRUE if everything went ok
+ FALSE if memory couldn't be allocated
+
+--*/
+{
+
+ CTEPagedCode();
+
+ pFile->f_BackUp = CTEAllocMem( MAX_LMHOSTS_LINE ) ;
+ if (pFile->f_BackUp == NULL )
+ {
+ return( FALSE );
+ }
+
+ CTEMemCopy( pFile->f_BackUp, pFile->f_buffer, LMHOSTS_READ_BUFF_SIZE );
+
+ return( TRUE );
+}
+
+
+//----------------------------------------------------------------------------
+
+VOID RestoreOldData( PLM_FILE pFile )
+/*++
+
+Routine Description:
+
+ This function restores all the data we backed up in BackupCurrentData
+
+Arguments:
+
+ pFile - LMfile pointer
+
+Return Value:
+
+ TRUE if everything went ok
+ FALSE if memory couldn't be allocated
+
+--*/
+{
+
+ CTEPagedCode();
+
+ CTEMemCopy( pFile->f_buffer, pFile->f_BackUp, LMHOSTS_READ_BUFF_SIZE );
+
+ CTEFreeMem( pFile->f_BackUp ) ;
+
+}
+
+
diff --git a/private/ntos/nbt/vxd/limit.txt b/private/ntos/nbt/vxd/limit.txt
new file mode 100644
index 000000000..726b7c7d7
--- /dev/null
+++ b/private/ntos/nbt/vxd/limit.txt
@@ -0,0 +1,51 @@
+
+============================================================================
+ NBT Limitations
+============================================================================
+
+This document lists the currently known limitations of the NBT Vxd.
+
+* The following Netbios commands are not supported:
+
+ NCBENUM
+ NCBLANSTALERT
+ NCBACTION
+
+ NCBSEND_RCVANY (Transceive) - Not necessary to support
+
+* Permanent adapter name may not have all of its listens & calls on cleaned
+ up on reset
+
+* NCBCANCEL only supports cancelling the following NCBs:
+ NCBRECV
+ NCBDGRECV
+ NCBDGRECVBC
+ NCBRECVANY
+ NCBLISTEN
+ NCBSEND
+ NCBSENDNA
+ NCBCHAINSEND
+ NCBCHAINSENDNA
+ NCBCALL
+
+* Call NCB opens a connection which will immediately be closed by NbtConnect.
+ Need to pass a flag (or NULL connect element) indicating we haven't set up
+ an inbound connection because we don't need to in this case.
+
+* On remote disconnects, if a send was just submitted, we may have to timeout
+ the TdiDisconnect because the FYN ACK may never get submitted (queued behind
+ send which can't complete because session is down).
+
+* Would be good to keep queue of preallocated buffers for Delayed calls
+
+* Name table numbers may not match in ASTAT command (Not OS code assigns
+ numbers based on the hashtable, the Vxd needs to use its name table
+
+* Extended lowercase characters in lmhosts file may not be upper cased
+ correctly (and thus not be usable). Need better upper case code.
+
+* If a program tries to exec or open a UNC that requires the LMHosts file,
+ nbt may not be able to satisfy the request because the InDos flag will
+ be set, thus nbt will not be able to read the lmhosts file. Normally
+ it will reschedule the read for some later time, but that will not work
+ in this instance. It retries 10 times then times out the request.
diff --git a/private/ntos/nbt/vxd/makefile b/private/ntos/nbt/vxd/makefile
new file mode 100644
index 000000000..a5c9e15c5
--- /dev/null
+++ b/private/ntos/nbt/vxd/makefile
@@ -0,0 +1,28 @@
+#
+#:ts=4
+# Makefile for the NBT component
+#
+ROOTDIR=..
+!include rules.mk
+
+all: svnbt svnbtd
+
+nodebug: svnbt cvnbt
+
+debug: svnbtd cvnbtd
+
+#
+# Don't build Windows 95 version from this tree any more.
+# Use QFE tree for Windows 95 bug fixes.
+# Use makefiles in VXD.000 directory for post-Windows 95
+# versions.
+#
+#all: svnbt svnbtd cvnbt cvnbtd
+#
+#nodebug: svnbt cvnbt
+#
+#debug: svnbtd cvnbtd
+#
+
+!include vnbtd.mk
+!include depend.mk
diff --git a/private/ntos/nbt/vxd/nbtinfo.c b/private/ntos/nbt/vxd/nbtinfo.c
new file mode 100644
index 000000000..ad267685f
--- /dev/null
+++ b/private/ntos/nbt/vxd/nbtinfo.c
@@ -0,0 +1,227 @@
+/**********************************************************************/
+/** Microsoft Windows/NT **/
+/** Copyright(c) Microsoft Corp., 1993 **/
+/**********************************************************************/
+
+/*
+ Nbtinfo.c
+
+ This file contains the NBT Info APIs
+
+
+
+ FILE HISTORY:
+ Johnl 13-Dec-1993 Created
+
+*/
+
+
+#include <nbtprocs.h>
+#include <dhcpinfo.h>
+#include <nbtinfo.h>
+
+/*******************************************************************
+
+ NAME: AddrChngNotification
+
+ SYNOPSIS: Notification handler called by Dhcp when an IpAddress
+ lease has expired or changed.
+
+ ENTRY: Context - Pointer to device context
+ OldIpAddress - in network order
+ NewIpAddress - in network order
+ NewMask - in network order
+
+ NOTES:
+
+ HISTORY:
+ Johnl 21-Dec-1993 Created
+
+********************************************************************/
+
+VOID AddrChngNotification( PVOID Context,
+ ULONG OldIpAddress,
+ ULONG NewIpAddress,
+ ULONG NewMask )
+{
+ tDEVICECONTEXT * pDeviceContext = (tDEVICECONTEXT*) Context ;
+ TDI_STATUS tdistatus ;
+ NTSTATUS status ;
+ ULONG IpBuff[4] ;
+ UINT Size ;
+ ULONG TmpNodeType;
+
+ DbgPrint("DhcpNotification: Nbt being notified of IP Address change by DHCP\r\n") ;
+
+ //
+ // NBT assumes the address goes to zero then comes up on the new
+ // address, so if the address is going to a new address (not to
+ // zero first) then fake it.
+ //
+
+ if ( NewIpAddress && pDeviceContext->IpAddress )
+ {
+ if ( status = NbtNewDhcpAddress( pDeviceContext, 0, 0 ) )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ("DhcpNotification: NbtSetNewDhcpAddress failed")) ;
+ }
+ }
+
+ if ( NewIpAddress == 0 )
+ {
+ if ( status = NbtNewDhcpAddress( pDeviceContext, 0, 0 ) )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ("DhcpNotification: NbtSetNewDhcpAddress failed")) ;
+ }
+ pDeviceContext->IpAddress = 0 ;
+ return ;
+ }
+
+ //
+ // Get all of the values that may change when the IP address changes.
+ // Currently this is only NBNS (scope & broadcast address are global
+ // NBT config parameters).
+ //
+
+ Size = sizeof( IpBuff ) ;
+ tdistatus = DhcpQueryOption( NewIpAddress,
+ 44, // NBNS
+ IpBuff,
+ &Size ) ;
+
+ if ( tdistatus != TDI_SUCCESS &&
+ tdistatus != TDI_BUFFER_OVERFLOW )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ("DhcpNotification: Query on NBNS failed")) ;
+ }
+ else
+ {
+ if ( Size >= 4 )
+ pDeviceContext->lNameServerAddress = ntohl(IpBuff[0]) ;
+
+ if ( Size >= 8 )
+ pDeviceContext->lBackupServer = ntohl(IpBuff[1]) ;
+ }
+
+ //
+ // if the node type is set to Bnode by default then switch to Hnode if
+ // there are any WINS servers configured.
+ //
+ TmpNodeType = NodeType;
+
+ if ((NodeType & DEFAULT_NODE_TYPE) &&
+ (pDeviceContext->lNameServerAddress || pDeviceContext->lBackupServer))
+ {
+ NodeType = MSNODE;
+ if (TmpNodeType & PROXY)
+ NodeType |= PROXY;
+ }
+
+ //
+ // Now set the new IP address
+ //
+
+ status = NbtNewDhcpAddress( pDeviceContext,
+ NewIpAddress,
+ NewMask ) ;
+
+ if ( NT_SUCCESS(status) )
+ {
+ if (pDeviceContext->IpAddress)
+ {
+ //
+ // Add the "permanent" name to the local name table.
+ //
+ status = NbtAddPermanentName(pDeviceContext);
+
+ if (!(NodeType & BNODE))
+ {
+ // the Ip address just changed and Dhcp may be informing
+ // us of a new Wins Server addresses, so refresh all the
+ // names to the new wins server
+ //
+ ReRegisterLocalNames();
+ }
+ else
+ {
+ //
+ // no need to refresh on a Bnode
+ //
+ LockedStopTimer(&NbtConfig.pRefreshTimer);
+ }
+ }
+ }
+
+ else
+ {
+ CDbgPrint( DBGFLAG_ERROR, ("DhcpNotification: NbtSetNewDhcpAddress failed")) ;
+ }
+
+
+
+}
+
+
+/*******************************************************************
+
+ NAME: CloseAddressesWithTransport
+
+ SYNOPSIS: Closes address objects on the passed in device
+
+ ENTRY: pDeviceContext - Device context to close
+
+ NOTES: Used after an IP address loses its DHCP lease by OS
+ independent code.
+
+ HISTORY:
+ Johnl 13-Dec-1993 Created
+
+********************************************************************/
+
+NTSTATUS
+CloseAddressesWithTransport(
+ IN tDEVICECONTEXT *pDeviceContext )
+{
+ TDI_REQUEST Request ;
+ NTSTATUS status;
+
+
+ if (pDeviceContext->pDgramFileObject)
+ {
+ Request.Handle.AddressHandle = pDeviceContext->pDgramFileObject ;
+ if ( TdiVxdCloseAddress( &Request ))
+ CDbgPrint( DBGFLAG_ERROR, ("NbtSetInfo: Warning - CloseAddress Failed\r\n")) ;
+ pDeviceContext->pDgramFileObject = NULL;
+ }
+
+ if (pDeviceContext->pNameServerFileObject)
+ {
+ Request.Handle.AddressHandle = pDeviceContext->pNameServerFileObject ;
+ if ( TdiVxdCloseAddress( &Request ))
+ CDbgPrint( DBGFLAG_ERROR, ("NbtSetInfo: Warning - CloseAddress Failed\r\n")) ;
+ pDeviceContext->pNameServerFileObject = NULL;
+ }
+
+ if (pDeviceContext->pSessionFileObject)
+ {
+ Request.Handle.AddressHandle = pDeviceContext->pSessionFileObject ;
+ if ( TdiVxdCloseAddress( &Request ))
+ CDbgPrint( DBGFLAG_ERROR, ("NbtSetInfo: Warning - CloseAddress Failed\r\n")) ;
+ pDeviceContext->pSessionFileObject = NULL;
+ }
+
+ if (pDeviceContext->hBroadcastAddress)
+ {
+ Request.Handle.ConnectionContext = pDeviceContext->hBroadcastAddress ;
+ status = NbtCloseAddress( &Request, NULL, pDeviceContext, NULL );
+ if ( !NT_SUCCESS(status) )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ("NbtSetInfo: Warning - Close Broadcast Address Failed\r\n")) ;
+ ASSERT(0);
+ }
+ }
+
+ return STATUS_SUCCESS ;
+}
+
+
diff --git a/private/ntos/nbt/vxd/ncb.c b/private/ntos/nbt/vxd/ncb.c
new file mode 100644
index 000000000..534a822e6
--- /dev/null
+++ b/private/ntos/nbt/vxd/ncb.c
@@ -0,0 +1,529 @@
+/**********************************************************************/
+/** Microsoft Windows/NT **/
+/** Copyright(c) Microsoft Corp., 1993 **/
+/**********************************************************************/
+
+/*
+ NCB.c
+
+ This file contains the NCB Handler that the VNetBios driver calls
+
+ FILE HISTORY:
+ Johnl 25-Mar-1993 Created
+
+*/
+
+#include <nbtprocs.h>
+#include <debug.h>
+
+#ifdef CHICAGO
+
+#include <shell.h>
+
+#include <netvxd.h>
+
+//
+// Do this so the VXDINLINE in the header file doesn't conflict
+// with the actual function declaration in this file.
+//
+#define VNBT_NCB_X VNBT_NCB_X_CALL
+#define VNBT_LANA_MASK VNBT_LANA_MASK_CALL
+#include <vnbt.h>
+#undef VNBT_LANA_MASK
+#undef VNBT_NCB_X
+
+#endif ;; CHICAGO
+
+LANA_ENTRY LanaTable[NBT_MAX_LANAS] ;
+
+/*******************************************************************
+
+ NAME: VNBT_NCB_X
+
+ SYNOPSIS: All NCBs submitted by the VNetBios driver come through
+ here
+
+ ENTRY: pNCB - Pointer to submitted NCB
+ Ipaddr - this parm is used only by nbtstat -A, which directly
+ calls into VNBT_NCB_X
+ ipaddress to which to send AdapterStatus to
+
+ RETURNS: NCB Return code
+
+ NOTES:
+
+ HISTORY:
+ Johnl 25-Mar-1993 Created
+
+********************************************************************/
+
+ULONG
+_stdcall
+VNBT_NCB_X( PNCB pNCB,
+ PUCHAR pzDnsName,
+ PULONG pIpAddress,
+ PVOID pExtended,
+ ULONG fFlag )
+{
+ BOOL fAsync ;
+ tDEVICECONTEXT * pDeviceContext = NULL ;
+ NTSTATUS status = STATUS_SUCCESS ;
+ uchar errNCB = NRC_GOODRET ;
+ PBLOCKING_NCB_CONTEXT pBlkNcbContext;
+ ULONG Ipaddr = pIpAddress ? pIpAddress[0] : 0;
+
+ if ( !pNCB )
+ return NRC_INVADDRESS ;
+
+ pDeviceContext = GetDeviceContext( pNCB ) ;
+ if ( pDeviceContext == NULL )
+ return NRC_BRIDGE ;
+
+ if (!pDeviceContext->fDeviceUp)
+ return NRC_BRIDGE ;
+
+ fAsync = !!(pNCB->ncb_command & ASYNCH) ;
+
+ if (
+ ( pzDnsName != NULL )
+ && ( pIpAddress != NULL )
+ )
+ {
+ if ( fAsync )
+ {
+ return DoDnsResolveDirect( pNCB, pzDnsName, pIpAddress );
+ }
+ else
+ {
+ return (pNCB->ncb_retcode = pNCB->ncb_cmd_cplt = NRC_ILLCMD);
+ }
+ }
+ else if (
+ ( pIpAddress != NULL )
+ && ( Ipaddr != 0 )
+ && ( ( pNCB->ncb_command & ~ASYNCH ) != NCBASTAT )
+ )
+ {
+ IpToAscii( Ipaddr, &pNCB->ncb_callname[0] );
+ }
+
+ if ( !fAsync )
+ {
+ pBlkNcbContext = CTEAllocMem( sizeof(BLOCKING_NCB_CONTEXT) );
+ if (!pBlkNcbContext)
+ {
+ DbgPrint("VNBT_NCB_X: couldn't alloc pBlkNcbContext 1") ;
+ return NRC_NORESOURCES;
+ }
+
+ pBlkNcbContext->Verify = NBT_VERIFY_BLOCKING_NCB;
+ InitializeListHead(&pBlkNcbContext->Linkage);
+ pBlkNcbContext->pNCB = pNCB;
+
+ pBlkNcbContext->pWaitNCBBlock = CTEAllocMem( sizeof(CTEBlockStruc) );
+ if (!pBlkNcbContext->pWaitNCBBlock)
+ {
+ CTEFreeMem(pBlkNcbContext);
+ DbgPrint("VNBT_NCB_X: couldn't alloc pBlkNcbContext 2") ;
+ return NRC_NORESOURCES;
+ }
+
+ pBlkNcbContext->fNCBCompleted = FALSE ;
+
+ //
+ // The completion routine uses this flag to know if the thread is
+ // blocked and needs to be signaled.
+ //
+ pBlkNcbContext->fBlocked = FALSE;
+
+ InsertTailList(&NbtConfig.BlockingNcbs,&pBlkNcbContext->Linkage);
+ }
+
+ DbgPrint("VNBT_NCB_X: NCB Commmand Rcvd: 0x") ;
+ DbgPrintNum( pNCB->ncb_command ) ; DbgPrint(", (") ;
+ DbgPrintNum( (ULONG) pNCB ) ; DbgPrint(")\r\n") ;
+
+ pNCB->ncb_retcode = NRC_PENDING ;
+ pNCB->ncb_cmd_cplt = NRC_PENDING ;
+
+ switch ( pNCB->ncb_command & ~ASYNCH )
+ {
+ case NCBDGSEND:
+ case NCBDGSENDBC:
+ status = VxdDgramSend( pDeviceContext, pNCB ) ;
+ errNCB = MapTDIStatus2NCBErr( status ) ;
+ break ;
+
+ case NCBDGRECV:
+ case NCBDGRECVBC:
+ errNCB = VxdDgramReceive( pDeviceContext, pNCB ) ;
+ break ;
+
+ case NCBRECVANY:
+ errNCB = VxdReceiveAny( pDeviceContext, pNCB ) ;
+ break ;
+
+ case NCBCALL:
+ errNCB = VxdCall( pDeviceContext, pNCB ) ;
+ break ;
+
+ case NCBHANGUP:
+ errNCB = VxdHangup( pDeviceContext, pNCB ) ;
+ break ;
+
+ case NCBLISTEN:
+ errNCB = VxdListen( pDeviceContext, pNCB ) ;
+ break ;
+
+ case NCBRECV:
+ errNCB = VxdReceive( pDeviceContext, pNCB, TRUE ) ;
+ break ;
+
+ case NCBSEND:
+ case NCBSENDNA:
+ case NCBCHAINSEND:
+ case NCBCHAINSENDNA:
+ errNCB = VxdSend( pDeviceContext, pNCB ) ;
+ break ;
+
+#if 0
+ case NCBTRANSV:
+ errNCB = VxdTransceive( pDeviceContext, pNCB ) ;
+ break ;
+#endif
+
+ case NCBADDGRNAME:
+ case NCBADDNAME:
+ errNCB = VxdOpenName( pDeviceContext, pNCB ) ;
+ break ;
+
+ case NCBDELNAME:
+ errNCB = VxdCloseName( pDeviceContext, pNCB ) ;
+ break ;
+
+ case NCBASTAT:
+ errNCB = VxdAdapterStatus( pDeviceContext, pNCB, Ipaddr ) ;
+ break ;
+
+ case NCBSSTAT:
+ errNCB = VxdSessionStatus( pDeviceContext, pNCB ) ;
+ break ;
+
+ case NCBFINDNAME:
+ errNCB = VxdFindName( pDeviceContext, pNCB ) ;
+ break ;
+
+ case NCBRESET:
+ errNCB = VxdReset( pDeviceContext, pNCB ) ;
+ break ;
+
+ case NCBCANCEL:
+ if ( DoDnsCancelDirect( pNCB ) )
+ {
+ errNCB = NRC_GOODRET;
+ }
+ else
+ {
+ errNCB = VxdCancel( pDeviceContext, pNCB ) ;
+ }
+ break ;
+
+ //
+ // The following are no-ops that return success for compatibility
+ //
+ case NCBUNLINK:
+ case NCBTRACE:
+ CTEIoComplete( pNCB, STATUS_SUCCESS, 0 ) ;
+ break ;
+
+ default:
+ DbgPrint("VNBT_NCB_X - Unsupported command: ") ;
+ DbgPrintNum( pNCB->ncb_command & ~ASYNCH ) ;
+ DbgPrint("\n\r") ;
+ errNCB = NRC_ILLCMD ; // Bogus error for now
+ break ;
+ }
+
+Exit:
+ //
+ // If we aren't pending then set the codes
+ //
+ if ( errNCB != NRC_PENDING &&
+ errNCB != NRC_GOODRET )
+ {
+#ifdef DEBUG
+ DbgPrint("VNBT_NCB_X - Returning ") ;
+ DbgPrintNum( errNCB ) ;
+ DbgPrint(" to NCB submitter\n\r") ;
+#endif
+ pNCB->ncb_retcode = errNCB ;
+ pNCB->ncb_cmd_cplt = errNCB ;
+
+ //
+ // Errored NCBs don't have the completion routine called, so we
+ // in essence, complete it here. Note this will only set the
+ // state for the last Wait NCB (all others get NRC_IFBUSY).
+ //
+ if ( !fAsync )
+ {
+ ASSERT(pBlkNcbContext->Verify == NBT_VERIFY_BLOCKING_NCB);
+ pBlkNcbContext->fNCBCompleted = TRUE ;
+ }
+ }
+ else
+ {
+ //
+ // Some components (AKA server) don't like returning pending
+ //
+ errNCB = NRC_GOODRET ;
+
+ }
+
+ //
+ // Block until NCB completion if this wasn't an async NCB
+ //
+ if ( !fAsync )
+ {
+ ASSERT(pBlkNcbContext->Verify == NBT_VERIFY_BLOCKING_NCB);
+ if ( !pBlkNcbContext->fNCBCompleted )
+ {
+ pBlkNcbContext->fBlocked = TRUE;
+ CTEInitBlockStruc( pBlkNcbContext->pWaitNCBBlock ) ;
+ CTEBlock( pBlkNcbContext->pWaitNCBBlock ) ;
+ }
+ else
+ {
+ RemoveEntryList(&pBlkNcbContext->Linkage);
+ CTEFreeMem(pBlkNcbContext->pWaitNCBBlock);
+ CTEFreeMem(pBlkNcbContext);
+ }
+ }
+
+ return errNCB ;
+}
+
+/*******************************************************************
+
+ NAME: GetDeviceContext
+
+ SYNOPSIS: Retrieves the device context associated with the lana
+ specified in the NCB
+
+ ENTRY: pNCB - NCB to get the device context for
+
+ RETURNS: Device context or NULL if not found
+
+ NOTES: It is assumed that LanaTable is filled sequentially
+ with no holes.
+
+ HISTORY:
+ Johnl 30-Aug-1993 Created
+
+********************************************************************/
+
+tDEVICECONTEXT * GetDeviceContext( NCB * pNCB )
+{
+ int i ;
+
+ if ( !pNCB )
+ return NULL ;
+
+ for ( i = 0; i < NBT_MAX_LANAS; i++)
+ {
+ if ( LanaTable[i].pDeviceContext->iLana == pNCB->ncb_lana_num)
+ return LanaTable[i].pDeviceContext;
+ }
+
+ return NULL;
+}
+
+/*******************************************************************
+
+ NAME: NbtWouldLoopback
+
+ SYNOPSIS: Returns a BOOL that specifies whether the input
+ IP address would loop back to the local machine
+
+ ENTRY: IpAddr
+
+ RETURNS: TRUE if Nbt is bound to this address
+
+ NOTES: It is assumed that LanaTable is filled sequentially
+ with no holes.
+
+ HISTORY:
+ EarleH 28-Mar-1996 Created
+
+********************************************************************/
+
+BOOL
+NbtWouldLoopback(
+ ULONG IpAddr
+)
+{
+ int i ;
+
+ for ( i = 0; i < NBT_MAX_LANAS; i++)
+ {
+ if (
+ ( LanaTable[i].pDeviceContext )
+ && ( LanaTable[i].pDeviceContext->IpAddress == IpAddr )
+ )
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************
+
+ NAME: VNBT_LANA_MASK
+
+ SYNOPSIS: Returns a bit mask of LANA numbers being handled
+ by vnbt, with a DNS server configured
+
+ ENTRY: none
+
+ RETURNS: Bit mask of LANA numbers being handled by vnbt
+
+ NOTES:
+
+ HISTORY:
+ EarleH 26-Feb-1996 Created
+
+********************************************************************/
+
+ULONG
+_stdcall
+VNBT_LANA_MASK(
+ )
+{
+ int i;
+ ULONG mask = 0;
+
+ for ( i = 0 ; i < NBT_MAX_LANAS; i++)
+ {
+ if (
+ ( LanaTable[i].pDeviceContext )
+ && ( LanaTable[i].pDeviceContext->fDeviceUp )
+ && ( LanaTable[i].pDeviceContext->lDnsServerAddress )
+ && ( LanaTable[i].pDeviceContext->lDnsServerAddress != LOOP_BACK )
+ )
+ {
+ mask |= 1 << LanaTable[i].pDeviceContext->iLana;
+ }
+ }
+
+ return mask;
+}
+
+/*******************************************************************
+
+ NAME: MapTDIStatus2NCBErr
+
+ SYNOPSIS: Maps a TDI_STATUS error value to an Netbios NCR error value
+
+ ENTRY: tdistatus - TDI Status to map
+
+ RETURNS: The mapped error
+
+ NOTES:
+
+ HISTORY:
+ Johnl 15-Apr-1993 Created
+
+********************************************************************/
+
+uchar MapTDIStatus2NCBErr( TDI_STATUS tdistatus )
+{
+ uchar errNCB ;
+ if ( tdistatus == TDI_SUCCESS )
+ return NRC_GOODRET ;
+ else if ( tdistatus == TDI_PENDING )
+ return NRC_PENDING ;
+
+
+ switch ( tdistatus )
+ {
+ case TDI_NO_RESOURCES:
+ errNCB = NRC_NORES ;
+ break ;
+
+ case STATUS_CANCELLED:
+ errNCB = NRC_CMDCAN ;
+ break ;
+
+ case TDI_INVALID_CONNECTION:
+ case STATUS_CONNECTION_DISCONNECTED:
+ errNCB = NRC_SCLOSED ;
+ break ;
+
+ case TDI_CONNECTION_ABORTED:
+ errNCB = NRC_SABORT ;
+ break ;
+
+ case STATUS_TOO_MANY_COMMANDS:
+ errNCB = NRC_TOOMANY ;
+ break ;
+
+ case STATUS_OBJECT_NAME_COLLISION:
+ case STATUS_SHARING_VIOLATION:
+ errNCB = NRC_DUPNAME ;
+ break ;
+
+ case STATUS_DUPLICATE_NAME:
+ errNCB = NRC_INUSE ;
+ break ;
+
+ //
+ // Call NCB submitted with a name that can't be found
+ //
+ case STATUS_BAD_NETWORK_PATH:
+ errNCB = NRC_NOCALL ;
+ break ;
+
+ case STATUS_REMOTE_NOT_LISTENING:
+ errNCB = NRC_REMTFUL ;
+ break ;
+
+ case TDI_TIMED_OUT:
+ errNCB = NRC_CMDTMO ;
+ break ;
+
+ //
+ // Where the transport has more data available but the NCB's buffer is
+ // full
+ //
+ case TDI_BUFFER_OVERFLOW:
+ errNCB = NRC_INCOMP ;
+ break ;
+
+ case STATUS_INVALID_BUFFER_SIZE:
+ errNCB = NRC_BUFLEN ;
+ break ;
+
+ case STATUS_NETWORK_NAME_DELETED:
+ errNCB = NRC_NAMERR ;
+ break ;
+
+ case STATUS_NRC_ACTSES:
+ errNCB = NRC_ACTSES ;
+ break ;
+
+ default:
+ DbgPrint("MapTDIStatus2NCBErr - Unmapped STATUS/TDI error - " ) ;
+ DbgPrintNum( tdistatus ) ;
+ DbgPrint("\n\r") ;
+
+ case STATUS_UNSUCCESSFUL:
+ case TDI_INVALID_STATE:
+ case STATUS_INVALID_PARAMETER: // Generally detected bad struct. signature
+ case STATUS_UNEXPECTED_NETWORK_ERROR:
+ errNCB = NRC_SYSTEM ;
+ break ;
+ }
+
+ return errNCB ;
+}
+
+
diff --git a/private/ntos/nbt/vxd/newdns.c b/private/ntos/nbt/vxd/newdns.c
new file mode 100644
index 000000000..9bcf78d4b
--- /dev/null
+++ b/private/ntos/nbt/vxd/newdns.c
@@ -0,0 +1,1019 @@
+/*++
+
+Copyright (c) 1989-1996 Microsoft Corporation
+
+Module Name:
+
+ DNS.c
+
+Abstract:
+
+ VxD-specific DNS routines.
+
+ This stuff will all be obsolete when we get proper services for
+ Windows. Then we will just call Winsock for DNS name resolution.
+
+Author:
+
+ Earle R. Horton (ERH) 13-Feb-1996
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+
+//----------------------------------------------------------------------------
+ ULONG
+DoDnsResolveDirect(
+ PNCB pncb,
+ PUCHAR pzDnsName,
+ PULONG pIpAddress
+)
+{
+ PDNS_DIRECT_WORK_ITEM_CONTEXT pContext;
+ PUCHAR pch;
+ tDEVICECONTEXT *pDeviceContext;
+ ULONG status;
+ CTELockHandle OldIrq;
+
+ pDeviceContext = GetDeviceContext( pncb ) ;
+
+ if ( pDeviceContext == NULL )
+ {
+ return NRC_BRIDGE ;
+ }
+
+ //
+ // If the primary DNS server is not defined, just return error.
+ // Return command timed out here.
+ //
+ if ( (!pDeviceContext->lDnsServerAddress) ||
+ ( pDeviceContext->lDnsServerAddress == LOOP_BACK) )
+ {
+ return( NRC_NOCALL );
+ }
+
+ pContext = CTEAllocMem( sizeof(DNS_DIRECT_WORK_ITEM_CONTEXT) );
+
+ if ( pContext == NULL )
+ {
+ return NRC_NORESOURCES;
+ }
+
+ CTEZeroMemory( pContext, sizeof(DNS_DIRECT_WORK_ITEM_CONTEXT) );
+
+ pContext->pDeviceContext = pDeviceContext;
+ pContext->pNCB = pncb;
+ pContext->pzDnsName = pzDnsName;
+ pContext->pIpAddress = pIpAddress;
+
+ pContext->TransactId = htons(GetTransactId() + DIRECT_DNS_NAME_QUERY_BASE );
+ pContext->pchDomainName = NbtConfig.pDomainName;
+ pContext->Flags = DNS_DIRECT_DNS_SERVER;
+
+ for ( pch = &pzDnsName[0] ; *pch++ != '\0' ; )
+ {
+ if ( pch[0] == '.' )
+ {
+ pContext->Flags |= DNS_DIRECT_NAME_HAS_DOTS;
+ pContext->pchDomainName = NULL;
+ }
+ }
+
+ //
+ // Put on the pending name queries list again so that when the query
+ // response comes in from DNS we can find the context.
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ InsertTailList(&NbtConfig.DNSDirectNameQueries,
+ &pContext->Linkage
+ );
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ status = UdpSendDNSBcastDirect( pContext,
+ (ULONG)pNbtGlobConfig->uRetryTimeout,
+ (ULONG)pNbtGlobConfig->uNumRetries
+ );
+
+ pncb->ncb_retcode = pncb->ncb_cmd_cplt = status ;
+
+ if ( status != NRC_PENDING )
+ {
+ pncb->ncb_retcode = pncb->ncb_cmd_cplt = status ;
+
+ DnsUnlinkAndCompleteDirect( pContext );
+ }
+ else
+ {
+ status = NRC_GOODRET;
+ }
+
+ return status;
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+UdpSendDNSBcastDirect(
+ IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext,
+ IN ULONG Timeout,
+ IN ULONG Retries
+)
+/*++
+
+Routine Description:
+
+ This routine sends a name query directed to the name server.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+History:
+
+ Adapted from UdpSendNSBcast() in "udpsend.c."
+
+ Earle R. Horton (earleh) March 18, 1996
+
+--*/
+{
+ NTSTATUS status;
+ tNAMEHDR *pNameHdr;
+ ULONG uLength;
+ ULONG uSentSize;
+ CTELockHandle OldIrq;
+ ULONG IpAddress;
+ tTIMERQENTRY *pTimerQEntry;
+ TDI_REQUEST TdiRequest;
+ PDNS_DIRECT_SEND_CONTEXT pSendContext;
+
+ pSendContext = CreateSendContextDirect(
+ pContext->pzDnsName,
+ pContext->pchDomainName,
+ (PVOID)&pNameHdr,
+ &uLength,
+ pContext);
+
+ if (pSendContext == NULL)
+ {
+ IF_DBG(NBT_DEBUG_NAMESRV)
+ KdPrint(("Nbt:Failed to Create Pdu to send to DNS.\n"));
+ return( NRC_NORES );
+ }
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ TdiRequest.Handle.AddressHandle = (PVOID)pContext->pDeviceContext->pNameServerFileObject;
+
+ // the completion routine is setup to free the pDgramTracker memory block
+ TdiRequest.RequestNotifyObject = SendDNSBcastDoneDirect;
+ TdiRequest.RequestContext = (PVOID)pSendContext;
+
+ // start the timer now...We didn't start it before because it could
+ // have expired during the dgram setup, perhaps before the Context was
+ // fully setup.
+ //
+ if (Timeout)
+ {
+ status = StartTimer(
+ Timeout,
+ pContext,
+ NULL,
+ DnsCompletionDirect,
+ NULL,
+ NULL,
+ (USHORT)Retries,
+ &pTimerQEntry
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ // we need to differentiate the timer failing versus lack
+ // of resources
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ CTEMemFree(pSendContext);
+
+ return( NRC_NORES );
+ }
+ //
+ // Cross link the nameaddr and the timer so we can stop the timer
+ // when the name query response occurs
+ //
+ pTimerQEntry->pCacheEntry = pContext;
+ pContext->pTimer = pTimerQEntry;
+ }
+
+ //
+ // in the event that DHCP has just removed the IP address, just cancel
+ // the request
+ //
+ if (pContext->pDeviceContext->IpAddress == 0)
+ {
+ StopTimer ( pContext->pTimer, NULL, NULL );
+ pContext->Flags |= DNS_DIRECT_CANCELLED;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ (VOID) TdiSendDatagram(
+ &TdiRequest,
+ &pSendContext->SendInfo,
+ uLength,
+ &uSentSize,
+ &pSendContext->SendBuffer,
+ NBT_NAME_SERVICE
+ );
+
+ return( NRC_PENDING );
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SendDNSBcastDoneDirect(
+ IN PVOID pSendContext,
+ IN NTSTATUS status,
+ IN ULONG lInfo
+)
+{
+ CTEMemFree(pSendContext);
+}
+
+//----------------------------------------------------------------------------
+ BOOL
+DoDnsCancelDirect(
+ PNCB pncb
+)
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PDNS_DIRECT_WORK_ITEM_CONTEXT
+ pContext;
+ CTELockHandle OldIrq;
+ BOOL RetVal = FALSE;
+
+ pHead = pEntry = &NbtConfig.DNSDirectNameQueries;
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pContext = CONTAINING_RECORD(pEntry,DNS_DIRECT_WORK_ITEM_CONTEXT,Linkage);
+ if ( pContext->pNCB == pncb )
+ {
+ StopTimer ( pContext->pTimer, NULL, NULL );
+ pContext->Flags |= DNS_DIRECT_CANCELLED;
+ RetVal = TRUE;
+ break;
+ }
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ return RetVal;
+}
+
+//----------------------------------------------------------------------------
+/*++
+
+Routine Description:
+
+ This routine is called by the timer code when the timer expires. It must
+ decide if another name query should be sent to the DNS server, and if not,
+ then it completes the request.
+
+Arguments:
+
+
+Notes:
+--*/
+ VOID
+DnsCompletionDirect(
+ PVOID pvContext,
+ PVOID pvContext2,
+ tTIMERQENTRY *pTimerQEntry
+)
+{
+ PDNS_DIRECT_WORK_ITEM_CONTEXT pContext;
+ tDEVICECONTEXT *pDeviceContext;
+
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ PCHAR pchDomainName;
+ USHORT Flags;
+ BOOL fOneMoreTry;
+
+ KdPrint(("DnsCompletion entered\r\n"));
+
+ pContext = (PDNS_DIRECT_WORK_ITEM_CONTEXT)pvContext;
+
+
+ // if the client completion routine is not set anymore, then the
+ // timer has been cancelled or completed and this routine should
+ // just clean up its buffers associated with the tracker (and return)
+ //
+ if (!pTimerQEntry)
+ {
+ // complete the request
+ LOCATION(0x52);
+ DnsUnlinkAndCompleteDirect( pContext );
+ return;
+ }
+
+
+ //
+ // to prevent a client from stopping the timer and deleting the
+ // pContext, grab the lock and check if the timer has been stopped
+ //
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ pDeviceContext = pContext->pDeviceContext;
+
+ if (pTimerQEntry->Flags & TIMER_RETIMED)
+ {
+ //
+ // Got a wait ACK from the server.
+ //
+ pTimerQEntry->Flags &= ~TIMER_RETIMED;
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ //
+ // if we are not bound to this card than use a very short timeout
+ //
+ if (
+ (!pDeviceContext->pNameServerFileObject)
+ || (pContext->Flags & DNS_DIRECT_CANCELLED)
+ )
+ {
+ pTimerQEntry->DeltaTime = 10;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ return;
+ }
+
+ // If done with all the (3) retries with primary, try secondary DNS srvr
+ // If secondary not defined, or done with secondary as well, stop.
+ //
+
+ fOneMoreTry = TRUE;
+
+ if (!(--pTimerQEntry->Retries))
+ {
+ //
+ // if backup server is not defined, or if it is defined but we just
+ // finished trying backup server, go back and try primary server for
+ // "other domains"
+ // e.g. DNSDomains was defined as "msft.dom2.com,msft.dom3.com,msft.dom"
+ // We were pointing at msft.dom2.com. Now, we are done with that (and
+ // didn't get a response), so try msft.dom3.com
+ //
+ if ( ( !pDeviceContext->lDnsBackupServer ) ||
+ ( pDeviceContext->lDnsBackupServer == LOOP_BACK ) ||
+ ( pContext->Flags & DNS_DIRECT_DNS_BACKUP) )
+ {
+ //
+ // if we just got done trying primary domain name, try all the
+ // "other domains" specified
+ //
+ if (pContext->pchDomainName == NbtConfig.pDomainName)
+ {
+ pContext->pchDomainName = NbtConfig.pDNSDomains;
+ if ( pContext->pchDomainName )
+ {
+ pContext->Flags &= ~DNS_DIRECT_DNS_BACKUP;
+ pContext->Flags |= DNS_DIRECT_DNS_SERVER;
+ pTimerQEntry->Retries = NbtConfig.uNumRetries;
+ }
+ else
+ {
+ fOneMoreTry = FALSE;
+ }
+ }
+
+ //
+ // if we had already started on "other domains", advance to the
+ // next domain within "other domains"
+ //
+ else if ( pContext->pchDomainName )
+ {
+ pchDomainName = pContext->pchDomainName;
+ while( *pchDomainName != ',' && // dom names separated by comma
+ *pchDomainName != ' ' && // or space
+ *pchDomainName != '\0' )
+ {
+ pchDomainName++;
+ }
+
+ if ( *pchDomainName == '\0' )
+ fOneMoreTry = FALSE;
+ else
+ {
+ pchDomainName++;
+ pContext->pchDomainName = pchDomainName;
+ pContext->Flags &= ~DNS_DIRECT_DNS_BACKUP;
+ pContext->Flags |= DNS_DIRECT_DNS_SERVER;
+ pTimerQEntry->Retries = NbtConfig.uNumRetries;
+ }
+ }
+ else
+ {
+ fOneMoreTry = FALSE;
+ }
+ }
+
+ // ok, prepare to try the backup server
+ else
+ {
+ pTimerQEntry->Retries = NbtConfig.uNumRetries;
+
+ pContext->Flags &= ~DNS_DIRECT_DNS_SERVER;
+ pContext->Flags |= DNS_DIRECT_DNS_BACKUP;
+ }
+ }
+
+ // we aren't done yet: send one more query and restart the timer
+ if (fOneMoreTry)
+ {
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ status = UdpSendDNSBcastDirect( pContext, 0, 0 );
+
+ pTimerQEntry->Flags |= TIMER_RESTART;
+
+ KdPrint(("One more DNS query sent out\r\n"));
+ }
+
+ // yup, all done: didn't find the name!
+ else
+ {
+ pTimerQEntry->Flags |= TIMER_RESTART;
+ StopTimer(pTimerQEntry,NULL,NULL);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+}
+
+//----------------------------------------------------------------------------
+/*++
+
+Routine Description:
+
+ This routine "actually" completes the request, either by completing the
+ asociated NCB with some kind of failure, or passing it off to the
+ main NCB processing code.
+
+Arguments:
+
+
+Notes:
+--*/
+ VOID
+DnsActualCompletionDirect(
+ IN NBT_WORK_ITEM_CONTEXT * pnbtContext
+)
+{
+ PDNS_DIRECT_WORK_ITEM_CONTEXT pContext = pnbtContext->pClientContext;
+ uchar errNCB = NRC_GOODRET ;
+ NCB * pNCB = pContext->pNCB;
+
+ if ( pNCB->ncb_cmd_cplt == NRC_PENDING )
+ {
+ //
+ // Failed to resolve the name, or request was cancelled.
+ //
+ if ( pContext->pIpAddress[0] == 0 )
+ {
+ errNCB = NRC_CMDTMO;
+ }
+ else if ( pContext->Flags & DNS_DIRECT_CANCELLED )
+ {
+ errNCB = NRC_CMDCAN;
+ }
+ else
+ {
+ errNCB = VNBT_NCB_X ( pContext->pNCB, NULL, pContext->pIpAddress, NULL, 0 );
+ }
+ if ( errNCB != NRC_GOODRET )
+ {
+ pNCB->ncb_retcode = pNCB->ncb_cmd_cplt = errNCB ;
+ //
+ // call the post-routine only if the post-routine has been specified!
+ //
+ if ( pNCB->ncb_post )
+ {
+ typedef void (CALLBACK * VXDNCBPost )( void ) ;
+ VXDNCBPost ncbpost = (VXDNCBPost) pNCB->ncb_post ;
+
+ //
+ // Clients are expecting EBX to point to the NCB (instead of
+ // pushing it on the stack...). The post routine may trash
+ // ebp also, so save it.
+ //
+ _asm pushad ;
+ _asm mov ebx, pNCB ;
+ ncbpost() ;
+ _asm popad ;
+ }
+ }
+ }
+
+ CTEMemFree(pContext);
+ CTEMemFree(pnbtContext);
+}
+
+//----------------------------------------------------------------------------
+ VOID
+DnsUnlinkAndCompleteDirect(
+ IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext
+)
+/*++
+
+Routine Description:
+
+ This routine unlinks and completes the request.
+
+Arguments:
+
+
+Notes:
+--*/
+{
+ RemoveEntryList(&pContext->Linkage);
+
+ VxdScheduleDelayedCall ( NULL,
+ pContext,
+ NULL,
+ DnsActualCompletionDirect,
+ pContext->pDeviceContext
+ );
+}
+
+//----------------------------------------------------------------------------
+ VOID
+ProcessDnsResponseDirect(
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN PVOID pSrcAddress,
+ IN tNAMEHDR UNALIGNED *pNameHdr,
+ IN LONG lNumBytes,
+ IN USHORT OpCodeFlags
+ )
+/*++
+
+Routine Description:
+
+ This function sets the state of the name being resolved appropriately
+ depending on whether DNS sends a positive or a negative response to our
+ query; calls the client completion routine and stops any more DNS queries
+ from going.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - STATUS_SUCCESS or STATUS_UNSUCCESSFUL
+
+--*/
+{
+ NTSTATUS status;
+ tDNS_QUERYRESP UNALIGNED *pQuery;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PDNS_DIRECT_WORK_ITEM_CONTEXT
+ pContext;
+ COMPLETIONCLIENT pClientCompletion;
+ PVOID Context;
+ PTRANSPORT_ADDRESS pSourceAddress;
+ ULONG SrcAddress;
+ ULONG IpAddress;
+ tTIMERQENTRY *pTimer = NULL;
+ CTELockHandle OldIrq1;
+ LONG lNameSize;
+ LONG lTraversedSoFar=0;
+ CHAR pJunkBuf[NETBIOS_NAME_SIZE];
+ PUCHAR pchQry;
+
+ // make sure this is a response
+
+ if ( !(OpCodeFlags & OP_RESPONSE) )
+ {
+ CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponseDirect: Bad OpCodeFlags\r\n"));
+
+ return;
+ }
+
+ pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
+ SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq1);
+
+ if ( ( pContext = FindContextDirect( pNameHdr->TransactId ) ) != NULL )
+
+ {
+ pContext->Flags |= DNS_DIRECT_ANSWERED;
+ if ( pTimer = pContext->pTimer )
+ {
+ //
+ // If the response we received doesn't resolve the name, we silently return,
+ // but make sure reties is set to 1 so that when timer fires again, we don't
+ // send another name query to the same server but instead timeout the
+ // attempt on this server
+ //
+ pTimer->Retries = 1;
+ }
+ //
+ // check the pdu size for errors
+ //
+ if (lNumBytes < DNS_MINIMUM_QUERYRESPONSE)
+ {
+ CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponseDirect: Bad lNumBytes\r\n"));
+ goto done;
+ }
+
+//
+// BUGBUG: should we require authoritative responses from DNS servers?
+//
+
+ //
+ // if it's a negative response, quit now!
+ //
+ if (IS_NEG_RESPONSE(OpCodeFlags))
+ {
+ goto done;
+ }
+
+ //
+ // if there is no answer section, return!
+ //
+ if ( !pNameHdr->AnCount )
+ {
+ CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponseDirect: No answer section\r\n"));
+ goto done;
+ }
+
+ //
+ // lNameSize is the length of the entire name, excluding the length byte
+ // for the first label (including length bytes of subsequent labels) and
+ // including the trailing 0 (tNAMEHDR struc takes care for 1st byte)
+ //
+ DnsExtractName( (PCHAR)&pNameHdr->NameRR.NameLength,
+ lNumBytes,
+ pJunkBuf,
+ &lNameSize
+ );
+ pchQry = (PUCHAR)&pNameHdr->NameRR.NetBiosName[lNameSize];
+
+ lTraversedSoFar += lNameSize;
+
+ //
+ // if the Question section is returned with the response then we have
+ // a little more work to do! In this case, pQuery is pointing at the
+ // beginning of the QTYPE field (end of the QNAME)
+ //
+ if ( pNameHdr->QdCount )
+ {
+ pchQry += sizeof(tQUESTIONMODS);
+ lTraversedSoFar += sizeof(tQUESTIONMODS);
+
+ // most common case: 1st byte will be 0xC0, which means next byte points
+ // to the actual name. We don't care about the name, so we skip over
+ // both the bytes
+ //
+ if ( (*pchQry) == PTR_TO_NAME )
+ {
+ pchQry += sizeof(tDNS_LABEL);
+ lTraversedSoFar += sizeof(tDNS_LABEL);
+ }
+
+ //
+ // if some implementation doesn't optimize and copies the whole name
+ // again, skip over the length of the name
+ //
+ else
+ {
+ pchQry += (lNameSize+1); // +1 because of the 1st length byte!
+ lTraversedSoFar += (lNameSize+1);
+ }
+ }
+
+ pQuery = (tDNS_QUERYRESP *)pchQry;
+
+ //
+ // if this rr is telling us about canonical name, skip over it and go to
+ // where the ipaddr is
+ //
+ if (ntohs(pQuery->RrType) == DNS_CNAME)
+ {
+ //
+ // since this is CNAME, there is no ipaddr. Instead, the data is the
+ // canonical name whose length we are adding, and subtract ipaddr's len
+ //
+ pchQry += (sizeof(tDNS_QUERYRESP) - sizeof(ULONG));
+ pchQry += ntohs(pQuery->Length);
+ lTraversedSoFar += ntohs(pQuery->Length) + sizeof(tDNS_QUERYRESP) - sizeof(ULONG);
+
+ ASSERT(lNumBytes > lTraversedSoFar);
+
+ // most common case: 1st byte will be 0xC0, which means next byte points
+ // to the actual name. We don't care about the name, so we skip over
+ // both the bytes
+ //
+ if ( (*pchQry) == PTR_TO_NAME )
+ {
+ pchQry += sizeof(tDNS_LABEL);
+ lTraversedSoFar += sizeof(tDNS_LABEL);
+ }
+
+ //
+ // if some implementation doesn't optimize and copies the whole name
+ // again, skip over the length of the name
+ //
+ else
+ {
+ // we have already taken the name out. we are calling this routine
+ // just to see how big the canonical name is (i.e.lNameSize), to skip
+ // past it
+ //
+ DnsExtractName( pchQry,
+ lNumBytes-lTraversedSoFar,
+ pJunkBuf,
+ &lNameSize
+ );
+
+ //
+ // lNameSize is the length of the entire name, excluding the length byte
+ // for the first label (including length bytes of subsequent labels) and
+ // including the trailing 0 (tNAMEHDR struc takes care for 1st byte)
+ //
+ pchQry += lNameSize+1; // +1 for the length byte of first label
+
+ }
+
+ pQuery = (tDNS_QUERYRESP *)pchQry;
+ }
+
+ // if we came this far, it's a positive response. do the needful.
+
+ IpAddress = ntohl(pQuery->IpAddress);
+
+ if ( !NbtWouldLoopback( IpAddress ) )
+ {
+ pContext->pIpAddress[0] = IpAddress;
+ }
+ else
+ {
+ pContext->Flags |= DNS_DIRECT_CANCELLED;
+ }
+
+ //
+ // Set the backup name server to be the main name server
+ // if we got a response from it.
+ //
+ if ( SrcAddress == pContext->pDeviceContext->lDnsBackupServer )
+ {
+ pContext->pDeviceContext->lDnsBackupServer =
+ pContext->pDeviceContext->lDnsServerAddress;
+
+ pContext->pDeviceContext->lDnsServerAddress = SrcAddress;
+ }
+
+ StopTimer(pTimer,NULL,NULL);
+ }
+
+done:
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq1);
+ return;
+}
+
+//----------------------------------------------------------------------------
+ PDNS_DIRECT_SEND_CONTEXT
+CreateSendContextDirect(
+ IN PCHAR pName,
+ IN PCHAR pchDomainName,
+ OUT PVOID *pHdrs,
+ OUT PULONG pLength,
+ IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext
+ )
+/*++
+
+Routine Description:
+
+ This routine builds a name query pdu
+
+Arguments:
+
+
+Return Value:
+
+ PDNS_DIRECT_SEND_CONTEXT - a pointer to a data structure used for the datagram
+ send that must be freed by the datagram send completion routine
+
+--*/
+{
+ tNAMEHDR *pNameHdr;
+ ULONG uLength;
+ ULONG uDomainNameSize;
+ tGENERALRR *pGeneral;
+ CTELockHandle OldIrq;
+ PDNS_DIRECT_SEND_CONTEXT
+ pSendContext;
+
+ uDomainNameSize = domnamelen(pchDomainName) + 1; // +1 for len byte
+ if (uDomainNameSize > 1)
+ {
+ uDomainNameSize++; // for the null byte
+ }
+
+ // size is size of the namehdr structure -1 for the NetbiosName[1]
+ // + the 32 bytes for the half ascii name +
+ // scope + size of the General RR structure
+ uLength = sizeof(DNS_DIRECT_SEND_CONTEXT) - 1
+ + uDomainNameSize
+ + sizeof(ULONG)
+ + strlen(pName)
+ + 1;
+
+ // Note that this memory must be deallocated when the send completes in
+ // SendDNSBcastDoneDirect()
+ pSendContext = NbtAllocMem((USHORT)uLength ,NBT_TAG('X'));
+
+ if (pSendContext)
+ {
+ CTEZeroMemory((PVOID)pSendContext,uLength);
+
+ pNameHdr = &pSendContext->NameHdr;
+
+ pNameHdr->TransactId = pContext->TransactId;
+ pNameHdr->QdCount = 1;
+ pNameHdr->AnCount = 0;
+ pNameHdr->NsCount = 0;
+
+ *pHdrs = (PVOID)pNameHdr;
+ *pLength = uLength = uLength - ( sizeof(DNS_DIRECT_SEND_CONTEXT) - sizeof(tNAMEHDR) );
+
+ // copy the netbios name ... adding the scope too
+ if ( pContext->Flags & DNS_DIRECT_NAME_HAS_DOTS )
+ {
+ char * p;
+ for ( p = pName ; *p != '.' ; p++ );
+ p[0] = '\0';
+ pGeneral = (tGENERALRR *)DnsStoreName(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ pName,
+ &p[1],
+ eDIRECT_DNS_NAME_QUERY);
+ p[0] = '.';
+ }
+ else
+ {
+ pGeneral = (tGENERALRR *)DnsStoreName(
+ (PCHAR)&pNameHdr->NameRR.NameLength,
+ pName,
+ pContext->pchDomainName,
+ eDIRECT_DNS_NAME_QUERY);
+ }
+
+
+ pGeneral->Question.QuestionTypeClass = htonl(QUEST_DNSINTERNET);
+
+ pNameHdr->OpCodeFlags = (FL_RECURDESIRE);
+
+ pNameHdr->ArCount = 0;
+
+ pSendContext->SendBuffer.pDgramHdr = pNameHdr;
+ pSendContext->SendBuffer.HdrLength = uLength;
+ pSendContext->SendBuffer.pBuffer = NULL;
+ pSendContext->SendBuffer.Length = 0;
+ pSendContext->SendInfo.RemoteAddressLength = sizeof(pSendContext->NameServerAddress);
+ pSendContext->SendInfo.RemoteAddress = (PTRANSPORT_ADDRESS)&pSendContext->NameServerAddress;
+ pSendContext->NameServerAddress.TAAddressCount = 1;
+ pSendContext->NameServerAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
+ pSendContext->NameServerAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+ pSendContext->NameServerAddress.Address[0].Address[0].sin_port = htons(NbtConfig.DnsServerPort);
+ if ( pContext->Flags & DNS_DIRECT_DNS_SERVER )
+ {
+ pSendContext->NameServerAddress.Address[0].Address[0].in_addr = htonl(pContext->pDeviceContext->lDnsServerAddress);
+ }
+ else
+ {
+ pSendContext->NameServerAddress.Address[0].Address[0].in_addr = htonl(pContext->pDeviceContext->lDnsBackupServer);
+ }
+ }
+
+ return(pSendContext);
+}
+
+//----------------------------------------------------------------------------
+ PDNS_DIRECT_WORK_ITEM_CONTEXT
+FindContextDirect(
+ USHORT TransactionId
+)
+/*++
+
+Routine Description:
+
+ This routine find the DNS_DIRECT_WORK_ITEM_CONTEXT having the given
+ TransactId
+
+Arguments:
+
+
+Return Value:
+
+ PDNS_DIRECT_SEND_CONTEXT - a pointer to the pContext having the given
+ TransactId, or NULL
+
+Notes:
+
+ Called with NbtConfig.JointLock held
+
+--*/
+{
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ PDNS_DIRECT_WORK_ITEM_CONTEXT
+ pContext;
+
+ pHead = pEntry = &NbtConfig.DNSDirectNameQueries;
+
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pContext = CONTAINING_RECORD(pEntry,DNS_DIRECT_WORK_ITEM_CONTEXT,Linkage);
+ if ( pContext->TransactId == TransactionId )
+ {
+ return pContext;
+ }
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------------
+ VOID
+IpToAscii(
+ IN DWORD IpAddress,
+ IN OUT PCHAR pcAscii
+)
+/*++
+
+Routine Description:
+
+ This routine converts an IP address to a NetBIOS name.
+
+Arguments:
+
+ DWORD IP address
+ PCHAR String pointer allocated for 16 bytes
+
+Return Value:
+
+ Note
+
+Notes:
+
+ This is a gigantic hack designed to get "net use \\<dnsname>"
+ working under Windows 95 OPK2 without destabilizing the existing
+ code base over much.
+
+--*/
+{
+ PCHAR pcIpAddressBytes = ( (PCHAR) &IpAddress ) + 3;
+ PCHAR pcIp = pcAscii;
+
+ int i,j,k,l,m;
+
+ memset ( pcAscii, 0x20, NETBIOS_NAME_SIZE );
+
+ for ( i = 4 ; i-- > 0 ; )
+ {
+
+ j = *pcIpAddressBytes-- & 0x000000FF;
+ k = j/100;
+ l = (j%100)/10;
+ m = j%10;
+
+ if ( k )
+ {
+ *pcIp++ = k + '0';
+ *pcIp++ = l + '0';
+ }
+
+ else if ( l )
+ {
+ *pcIp++ = l + '0';
+ }
+
+ *pcIp++ = m + '0';
+
+ if ( i )
+ {
+ *pcIp++ = '.';
+ }
+
+ }
+
+}
+
diff --git a/private/ntos/nbt/vxd/pageable.inc b/private/ntos/nbt/vxd/pageable.inc
new file mode 100644
index 000000000..8b13b5276
--- /dev/null
+++ b/private/ntos/nbt/vxd/pageable.inc
@@ -0,0 +1,36 @@
+;
+; Macro to define pageable code under Chicago and later
+; operating systems.
+;
+
+NBT_PAGEABLE_CODE_SEG MACRO
+
+ifdef CHICAGO
+
+VxD_PAGEABLE_CODE_SEG
+
+else
+
+VxD_CODE_SEG
+
+endif
+
+ endm
+
+
+
+
+
+NBT_PAGEABLE_CODE_ENDS MACRO
+
+ifdef CHICAGO
+
+VxD_PAGEABLE_CODE_ENDS
+
+else
+
+VxD_CODE_ENDS
+
+endif
+
+ endm
diff --git a/private/ntos/nbt/vxd/rules.mk b/private/ntos/nbt/vxd/rules.mk
new file mode 100644
index 000000000..831428e2f
--- /dev/null
+++ b/private/ntos/nbt/vxd/rules.mk
@@ -0,0 +1,4 @@
+#
+#:ts=4
+#
+!include ..\rules16.mk
diff --git a/private/ntos/nbt/vxd/tdiaddr.c b/private/ntos/nbt/vxd/tdiaddr.c
new file mode 100644
index 000000000..7b2727dfa
--- /dev/null
+++ b/private/ntos/nbt/vxd/tdiaddr.c
@@ -0,0 +1,184 @@
+//
+//
+// tdiaddr.c
+//
+// This file contains code relating to manipulation of address objects
+// that is specific to the VXD environment. It creates address endpoints
+// with the transport provider.
+
+#include <nbtprocs.h>
+#include <tdistat.h> // TDI error codes
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtTdiOpenAddress (
+ OUT PHANDLE pFileHandle,
+ OUT PDEVICE_OBJECT *ppDeviceObject,
+ OUT PFILE_OBJECT *ppFileObject,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN USHORT PortNumber,
+ IN ULONG IpAddress,
+ IN ULONG Flags
+ )
+/*++
+
+Routine Description:
+
+ Note: This synchronous call may take a number of seconds. It runs in
+ the context of the caller. The code Opens an Address object with the
+ transport provider and then sets up event handlers for Receive,
+ Disconnect, Datagrams and Errors.
+
+ The address data structures are found in tdi.h , but they are rather
+ confusing since the definitions have been spread across several data types.
+ This section shows the complete data type for Ip address:
+
+ typedef struct
+ {
+ int TA_AddressCount;
+ struct _TA_ADDRESS
+ {
+ USHORT AddressType;
+ USHORT AddressLength;
+ struct _TDI_ADDRESS_IP
+ {
+ USHORT sin_port;
+ USHORT in_addr;
+ UCHAR sin_zero[8];
+ } TDI_ADDRESS_IP
+
+ } TA_ADDRESS[AddressCount];
+
+ } TRANSPORT_ADDRESS
+
+ An EA buffer is allocated (for the IRP), with an EA name of "TransportAddress"
+ and value is a structure of type TRANSPORT_ADDRESS.
+
+Arguments:
+
+ bTCP - a boolean to say if we are openning a TCP port or a UDP port
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS ;
+ TA_IP_ADDRESS taip ; // This is really a TRANSPORT_ADDRESS
+ TDI_REQUEST tdirequest ;
+
+ DbgPrint("TdiOpenAddress called\n\r");
+
+
+ taip.TAAddressCount = 1 ;
+ taip.Address[0].AddressLength = sizeof( TDI_ADDRESS_IP ) ;
+ taip.Address[0].AddressType = TDI_ADDRESS_TYPE_IP ;
+ taip.Address[0].Address[0].sin_port = htons(PortNumber); // put in network order
+ taip.Address[0].Address[0].in_addr = htonl(IpAddress);
+ CTEZeroMemory( taip.Address[0].Address[0].sin_zero,
+ sizeof( taip.Address[0].Address[0].sin_zero ) ) ;
+
+ #define TCP_PORT 6
+ #define UDP_PORT 17
+ status = TdiVxdOpenAddress( &tdirequest,
+ (PTRANSPORT_ADDRESS) &taip,
+ Flags & SESSION_FLAG ? TCP_PORT : UDP_PORT,
+ NULL ) ;
+
+ if ( status == TDI_SUCCESS )
+ {
+ HANDLE hAddress = tdirequest.Handle.AddressHandle ;
+
+ //
+ // As a VXD, the p*FileObject in the DeviceContext structure will
+ // contain the TDI Address. For compatibility with NT (may want
+ // to change this with an environment specific address).
+ //
+ *ppFileObject = (PFILE_OBJECT) hAddress ;
+
+ if (Flags & TCP_FLAG)
+ {
+ // TCP port needs several event handlers for connection
+ // management
+ status = TdiVxdSetEventHandler(
+ hAddress,
+ TDI_EVENT_RECEIVE,
+ (PVOID)TdiReceiveHandler,
+ (PVOID)pDeviceContext);
+
+ ASSERTMSG( "Failed to set Receive event handler",
+ status == TDI_SUCCESS );
+
+ status = TdiVxdSetEventHandler(
+ hAddress,
+ TDI_EVENT_DISCONNECT,
+ (PVOID)TdiDisconnectHandler,
+ (PVOID)pDeviceContext);
+ ASSERTMSG( "Failed to set Disconnect event handler",
+ status == TDI_SUCCESS);
+
+ // only set an connect handler if the session flag is set.
+ // In this case the address being opened is the Netbios session
+ // port 139
+ if (Flags & SESSION_FLAG)
+ {
+ status = TdiVxdSetEventHandler(
+ hAddress,
+ TDI_EVENT_CONNECT,
+ (PVOID)TdiConnectHandler,
+ (PVOID)pDeviceContext);
+
+ ASSERTMSG((PUCHAR)"Failed to set Receive event handler",
+ status == TDI_SUCCESS );
+ }
+ }
+ else
+ {
+ // Datagram ports only need this event handler
+ if (PortNumber == NBT_DATAGRAM_UDP_PORT)
+ {
+ // Datagram Udp Handler
+ status = TdiVxdSetEventHandler(
+ hAddress,
+ TDI_EVENT_RECEIVE_DATAGRAM,
+ (PVOID)TdiRcvDatagramHandler,
+ (PVOID)pDeviceContext);
+ ASSERTMSG("Failed to set Receive Datagram event handler",
+ status == TDI_SUCCESS );
+ }
+ else
+ {
+ // Name Service Udp handler
+ status = TdiVxdSetEventHandler(
+ hAddress,
+ TDI_EVENT_RECEIVE_DATAGRAM,
+ (PVOID)TdiRcvNameSrvHandler,
+ (PVOID)pDeviceContext);
+ ASSERTMSG( "Failed to set Receive Datagram event handler",
+ status == TDI_SUCCESS );
+ }
+ }
+
+ status = TdiVxdSetEventHandler(
+ hAddress,
+ TDI_EVENT_ERROR,
+ (PVOID)TdiErrorHandler,
+ (PVOID)pDeviceContext);
+ ASSERTMSG("Failed to set Error event handler",
+ status == TDI_SUCCESS );
+
+
+ }
+
+#ifdef DEBUG
+ if ( status != STATUS_SUCCESS )
+ {
+ DbgPrint("NbtTdiOpenAddress: status == ") ;
+ DbgPrintNum( status ) ; DbgPrint("\n\r") ;
+ }
+#endif
+ return(status);
+}
+
+
diff --git a/private/ntos/nbt/vxd/tdicnct.c b/private/ntos/nbt/vxd/tdicnct.c
new file mode 100644
index 000000000..fea0ba781
--- /dev/null
+++ b/private/ntos/nbt/vxd/tdicnct.c
@@ -0,0 +1,328 @@
+//
+//
+// NBTCONNCT.C
+//
+// This file contains code relating to opening connections with the transport
+// provider. The Code is NT specific.
+
+#include <nbtprocs.h>
+
+void DummyCompletion( PVOID pContext ) ;
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtTdiOpenConnection (
+ IN tLOWERCONNECTION *pLowerConn,
+ IN tDEVICECONTEXT *pDeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine opens a connection with the transport provider.
+
+Arguments:
+
+ pLowerConn - Pointer to where the handle to the Transport for this virtual
+ connection should be stored.
+
+ pNbtConfig - the name of the adapter to connect to is in this structure
+
+Return Value:
+
+ Status of the operation.
+
+ pLowerConn->pFileObject will contain the Connection ID of a successful open
+
+--*/
+{
+ NTSTATUS status;
+ TDI_REQUEST Request ;
+ DbgPrint("NbtTdiOpenConnection Entered\n\r") ;
+
+ CTEZeroMemory(pLowerConn,sizeof(tLOWERCONNECTION));
+ pLowerConn->State = NBT_IDLE;
+ pLowerConn->pDeviceContext = pDeviceContext;
+ pLowerConn->RefCount = 1;
+ pLowerConn->LockNumber = LOWERCON_LOCK;
+ pLowerConn->Verify = NBT_VERIFY_LOWERCONN;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+
+ //
+ // Use the lower connection as the context
+ //
+ status = TdiVxdOpenConnection( &Request, pLowerConn ) ;
+#ifdef DEBUG
+ if ( status != TDI_SUCCESS )
+ {
+ DbgPrint("NbtTdiOpenConnection: OpenConnection failed, error ") ;
+ DbgPrintNum( status ) ;
+ DbgPrint("\n\r") ;
+ }
+#endif
+
+
+ //
+ // Store the handle in the Lower Connection for future reference
+ //
+ pLowerConn->pFileObject = Request.Handle.ConnectionContext ;
+ DbgPrint("TdiVxdOpenConnection - pLower Conn: 0x") ;
+ DbgPrintNum((ULONG) pLowerConn ) ;
+ DbgPrint( " Connection ID: 0x") ;
+ DbgPrintNum( (ULONG) Request.Handle.ConnectionContext ) ; DbgPrint("\r\n") ;
+
+ return status;
+} /* NbtTdiOpenConnection */
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtTdiAssociateConnection(
+ IN PFILE_OBJECT pFileObject,
+ IN HANDLE Handle
+ )
+/*++
+
+Routine Description:
+
+ This routine associates an open connection with the address object.
+
+Arguments:
+
+
+ pFileObject - the connection file object (actually a connection ID)
+ Handle - the address object to associate the connection with
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ TDI_REQUEST Request ;
+ DbgPrint("NbtTdiAssociateConnection Entered\n\r") ;
+
+ Request.Handle.ConnectionContext = (CONNECTION_CONTEXT) pFileObject ;
+ status = TdiVxdAssociateAddress( &Request, Handle ) ;
+
+#ifdef DEBUG
+ if ( status != TDI_SUCCESS )
+ {
+ DbgPrint("NbtTdiAssociateConnection: AssociateAddress failed, error ") ;
+ DbgPrintNum( status ) ;
+ DbgPrint("\n\r") ;
+ }
+#endif
+ return status;
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiOpenandAssocConnection(
+ IN tCONNECTELE *pConnEle,
+ IN tDEVICECONTEXT *pDeviceContext,
+ IN ULONG PortNumber
+ )
+/*++
+
+Routine Description:
+
+ This routine opens and associates an open connection
+
+Arguments:
+
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ NTSTATUS status;
+ CTELockHandle OldIrq;
+ PDEVICE_OBJECT pDeviceObject;
+ tLOWERCONNECTION *pLowerConn;
+
+ DbgPrint("TdiOpenandAssocConnection Entered\n\r") ;
+
+ // allocate memory for the lower connection block.
+ pConnEle->pLowerConnId = (PVOID)CTEAllocMem(sizeof(tLOWERCONNECTION));
+ if (!pConnEle->pLowerConnId)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // fill in the lower connection element to point to the upper one and
+ // vice versa
+ //
+ pLowerConn = pConnEle->pLowerConnId;
+
+ //
+ // pLowerConn->pFileObject will contain the connection ID after
+ // this call
+ //
+ status = NbtTdiOpenConnection(pLowerConn,pDeviceContext);
+ if (!NT_SUCCESS(status))
+ {
+ CTEMemFree((PVOID)pConnEle->pLowerConnId);
+ return(status);
+ }
+
+ pLowerConn->pUpperConnection = pConnEle;
+ pLowerConn->State = NBT_CONNECTING;
+
+
+ if (NT_SUCCESS(status))
+ {
+
+
+ // Open an address object (aka port)
+ //
+ status = NbtTdiOpenAddress(
+ NULL, //&pLowerConn->AddrFileHandle,
+ &pDeviceObject, // dummy argument, not used here
+ &pLowerConn->pAddrFileObject, // Address Handle
+ pDeviceContext,
+ (USHORT)PortNumber, // port
+ pDeviceContext->IpAddress,
+ TCP_FLAG | SESSION_FLAG );
+
+ if (NT_SUCCESS(status))
+ {
+ // now associate the two
+ status = NbtTdiAssociateConnection(
+ pLowerConn->pFileObject,
+ pLowerConn->pAddrFileObject);
+ if (NT_SUCCESS(status))
+ {
+ //
+ // put the lower connection on the Q of active lower connections for
+ // this device
+ //
+ CTESpinLock(pDeviceContext,OldIrq);
+ InsertTailList(&pDeviceContext->LowerConnection,&pLowerConn->Linkage);
+ CTESpinFree(pDeviceContext,OldIrq);
+
+ return(status);
+ }
+
+ REQUIRE( NT_SUCCESS( NbtTdiCloseAddress( pLowerConn )) ) ;
+ }
+
+ REQUIRE( NT_SUCCESS( NbtTdiCloseConnection( pLowerConn )) ) ;
+ }
+
+ // Error Path... delete memory
+ //
+ pConnEle->pLowerConnId = NULL;
+ CTEMemFree((PVOID)pLowerConn);
+
+ return(status);
+}
+
+//----------------------------------------------------------------------------
+
+NTSTATUS
+NbtTdiCloseConnection(
+ IN tLOWERCONNECTION * pLowerConn
+ )
+/*++
+
+Routine Description:
+
+ This routine closes a TDI connection
+
+Arguments:
+
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ NTSTATUS status ;
+ TDI_REQUEST Request ;
+ DbgPrint("NbtTdiCloseConnection Entered\n\r") ;
+
+ ASSERT( pLowerConn != NULL ) ;
+
+ Request.Handle.ConnectionContext = pLowerConn->pFileObject ;
+ Request.RequestNotifyObject = DummyCompletion ;
+ Request.RequestContext = NULL ;
+
+ status = TdiVxdCloseConnection( &Request ) ;
+
+#ifdef DEBUG
+ if ( !NT_SUCCESS( status ))
+ {
+ DbgPrint("NbtCloseConnection: Warning - returning 0x") ;
+ DbgPrintNum( status ) ; DbgPrint("\r\n") ;
+ }
+#endif
+ DbgPrint("TdiVxdCloseConnection - pLowerConn: 0x") ;
+ DbgPrintNum((ULONG) pLowerConn ) ;
+ DbgPrint(" Connection ID: 0x") ;
+ DbgPrintNum( (ULONG) Request.Handle.ConnectionContext ) ; DbgPrint("\r\n") ;
+ return status ;
+}
+
+//----------------------------------------------------------------------------
+NTSTATUS
+NbtTdiCloseAddress(
+ IN tLOWERCONNECTION * pLowerConn
+ )
+/*++
+
+Routine Description:
+
+ This routine closes a TDI address
+
+Arguments:
+
+
+Return Value:
+
+ Status of the operation.
+
+--*/
+{
+ DbgPrint("NbtTdiCloseAddress Entered\n\r") ;
+ ASSERT( pLowerConn != NULL ) ;
+
+ return CloseAddress( pLowerConn->pAddrFileObject ) ;
+}
+
+//----------------------------------------------------------------------------
+NTSTATUS CloseAddress( HANDLE hAddress )
+{
+ NTSTATUS status ;
+ TDI_REQUEST Request ;
+ DbgPrint("CloseAddress Entered\n\r") ;
+
+ Request.Handle.AddressHandle = hAddress ;
+ Request.RequestNotifyObject = DummyCompletion ;
+ Request.RequestContext = NULL ;
+
+ status = TdiVxdCloseAddress( &Request ) ;
+
+#ifdef DEBUG
+ if ( !NT_SUCCESS( status ))
+ {
+ DbgPrint("CloseAddress: Warning - returning 0x") ;
+ DbgPrintNum( status ) ; DbgPrint("\r\n") ;
+ }
+#endif
+ return status ;
+}
+
+
+//
+// Dummy completion routine for Close connection and Close Address
+//
+void DummyCompletion( PVOID pContext )
+{
+ return ;
+}
diff --git a/private/ntos/nbt/vxd/tdihndlr.c b/private/ntos/nbt/vxd/tdihndlr.c
new file mode 100644
index 000000000..f5a9d5425
--- /dev/null
+++ b/private/ntos/nbt/vxd/tdihndlr.c
@@ -0,0 +1,1719 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Tdihndlr.c
+
+Abstract:
+
+
+ This file contains the TDI handlers that are setup for Connects,
+ Receives, Disconnects, and Errors on an address object (in tdiaddr.c).
+
+ This file represents the TDI interface on the Bottom of NBT. Therefore
+ the code basically decodes the incoming information and passes it to
+ a non-Os specific routine to do what it can. Upon return from that
+ routine additional Os specific work may need to be done.
+
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+ John Ludeman (JohnL) 04-10-93 - Rewrote for VXD
+
+Revision History:
+
+--*/
+
+#include "nbtprocs.h"
+#include "ctemacro.h"
+
+//
+// The event receive buffer takes a pointer to a flags variable that will
+// always be the same, so just use the same variable
+//
+static USHORT usFlags = TDI_RECEIVE_NORMAL ;
+
+VOID
+AcceptCompletionRoutine(
+ IN PVOID pContext,
+ IN uint tdistatus,
+ IN uint extra
+ );
+VOID
+NewSessionCompletionRoutine (
+ IN PVOID pContext,
+ IN uint tdistatus,
+ IN uint extra
+ );
+NTSTATUS
+Reindicate(
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu
+ );
+
+//
+// This ntohl swaps just three bytes, since the 4th byte could be a session
+// keep alive message type.
+//
+__inline long
+myntohl(long x)
+{
+ return((((x) >> 24) & 0x000000FFL) |
+ (((x) >> 8) & 0x0000FF00L) |
+ (((x) << 8) & 0x00FF0000L));
+}
+
+//----------------------------------------------------------------------------
+ TDI_STATUS
+TdiReceiveHandler (
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu,
+ OUT EventRcvBuffer * pevrcvbuf
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive event indication handler.
+
+ It is called when an session packet arrives from the network. It calls
+ a non OS specific routine to decide what to do. That routine passes back
+ either a RcvElement (buffer) or a client rcv handler to call.
+
+Arguments:
+
+ IN PVOID ReceiveEventContext - Context provided for this event when event set
+ IN PVOID ConnectionContext - Connection Context, (pLowerConnection)
+ IN USHORT ReceiveFlags - Flags describing the message
+ IN ULONG BytesIndicated - Number of bytes available at indication time
+ IN ULONG BytesAvailable - Number of bytes available to receive
+ OUT PULONG BytesTaken - Number of bytes consumed by redirector.
+ IN PVOID pTsdu - Data from remote machine.
+ OUT EvenRcvBuffer *ppBuffer - Receive buffer to fill if set
+
+
+Return Value:
+
+ TDI_STATUS - Status of receive operation
+
+--*/
+
+{
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnectEle;
+ PRCV_CONTEXT prcvCont = NULL ;
+ NTSTATUS status;
+ ULONG PduSize;
+ ULONG RemainingPdu;
+
+ DbgPrint("TRH Entered (ConnectionContext = 0x") ;
+ DbgPrintNum( (ULONG) ConnectionContext) ; DbgPrint(")\r\n") ;
+
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+
+ pLowerConn->BytesRcvd += BytesAvailable;
+
+ //
+ // check if this is another part of a session pdu
+ //
+ if (pLowerConn->State == NBT_SESSION_UP)
+ {
+ DbgPrint("\tTRH: Session status is UP, Bytes: available, indicated: 0x") ;
+ DbgPrintNum( BytesAvailable ) ; DbgPrint(" 0x") ;
+ DbgPrintNum( BytesIndicated ) ;
+ DbgPrint("\r\n") ;
+
+ pConnectEle = pLowerConn->pUpperConnection;
+ pConnectEle->BytesInXport = BytesAvailable ;
+ *BytesTaken = 0 ;
+
+ DbgPrint("\tTRH: BytesInXport: 0x") ;
+ DbgPrintNum( pConnectEle->BytesInXport ) ;
+ DbgPrint("\r\n") ;
+
+
+ //
+ // ** RECEIVING A PDU STATE **
+ //
+
+ switch (pLowerConn->StateRcv)
+ {
+ case NORMAL:
+ //
+ // check indication and if less than the session header,
+ // copy to the session header buffer and go to Indic_buffer state
+ // and wait for the next indication. This is a rare case (and a pain
+ // in the butt).
+ //
+ if (BytesIndicated < sizeof(tSESSIONHDR))
+ {
+ ASSERT( pLowerConn->BytesInHdr == 0 ) ;
+ DbgPrint("\tTRH - NORMAL case: Not enough for session header, requesting 0x") ;
+ DbgPrintNum( sizeof( pLowerConn->Hdr ) ) ;
+ DbgPrint(" bytes\r\n") ;
+
+
+ if ( !GetRcvContext( &prcvCont))
+ return STATUS_INSUFFICIENT_RESOURCES ;
+
+ InitRcvContext( prcvCont, pLowerConn, NULL ) ;
+ prcvCont->usFlags = TDI_RECEIVE_NORMAL;
+ pevrcvbuf->erb_buffer = &prcvCont->ndisBuff ;
+ pevrcvbuf->erb_rtn = (CTEReqCmpltRtn) NewSessionCompletionRoutine ;
+ pevrcvbuf->erb_size = sizeof( pLowerConn->Hdr ) ;
+ pevrcvbuf->erb_context = prcvCont ;
+ pevrcvbuf->erb_flags = &usFlags ;
+ InitNDISBuff( pevrcvbuf->erb_buffer,
+ &pLowerConn->Hdr,
+ sizeof(pLowerConn->Hdr),
+ NULL ) ;
+
+ pLowerConn->StateRcv = INDICATE_BUFFER;
+
+ //
+ // Okay to use pIrpRcv here as it will only be completed if
+ // the state is FILL_IRP
+ //
+ pConnectEle->pIrpRcv = (PCTE_IRP) prcvCont ;
+
+ return TDI_MORE_PROCESSING ;
+ }
+
+ PduSize = myntohl(((tSESSIONHDR *)pTsdu)->UlongLength)
+ + sizeof(tSESSIONHDR);
+ DbgPrint("\tTRH: New message; Opcode, PduSize + hdr : 0x") ;
+ DbgPrintNum( ((tSESSIONHDR *)pTsdu)->Type ) ; DbgPrint(" 0x") ;
+ DbgPrintNum( PduSize ) ; DbgPrint("\r\n") ;
+
+ //
+ // Indicate to the client
+ //
+ ASSERT( PduSize >= sizeof(tSESSIONHDR)) ;
+ status = RcvHandlrNotOs(
+ ReceiveEventContext,
+ ConnectionContext,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ pTsdu,
+ &prcvCont
+ );
+
+ ASSERT( *BytesTaken <= pConnectEle->BytesInXport ) ;
+ ASSERT( *BytesTaken <= BytesIndicated);
+ pConnectEle->BytesInXport -= *BytesTaken;
+ BytesIndicated -= *BytesTaken;
+ BytesAvailable -= *BytesTaken;
+ ((BYTE*)pTsdu) += *BytesTaken ;
+
+ DbgPrint("\tTRH: RcvHandlrNotOs returned, BytesTaken: 0x") ;
+ DbgPrintNum( *BytesTaken ) ;
+ DbgPrint("\r\n") ;
+
+ DbgPrint("\tTRH: RcvHandlrNotOs status, prcvCont: 0x") ;
+ DbgPrintNum( status ) ; DbgPrint(" 0x") ;
+ DbgPrintNum( (ULONG)prcvCont ) ; DbgPrint("\r\n") ;
+
+ if ( prcvCont )
+ {
+ ULONG BytesToCopy ;
+ ASSERT( status == STATUS_MORE_PROCESSING_REQUIRED );
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ //
+ // Record which session satisfied the request
+ //
+ prcvCont->pLowerConnId = pLowerConn ;
+ REQUIRE( !VxdFindLSN( pConnectEle->pClientEle->pDeviceContext,
+ pConnectEle,
+ &prcvCont->pNCB->ncb_lsn )) ;
+ //
+ // New message so strip session header
+ //
+ PduSize -= *BytesTaken ;
+ DbgPrint("\tTRH: Remaining PduSize = 0x") ;
+ DbgPrintNum( PduSize ) ; DbgPrint("\r\n") ;
+
+ DbgPrint("\tTRH: TotalPcktLen = 0x") ;
+ DbgPrintNum( pConnectEle->TotalPcktLen ) ; DbgPrint("\r\n") ;
+
+ BytesToCopy = min( pConnectEle->TotalPcktLen,
+ prcvCont->ndisBuff.Length ) ;
+
+ DbgPrint("\tTRH: BytesToCopy = 0x") ;
+ DbgPrintNum( BytesToCopy ) ; DbgPrint("\r\n") ;
+
+ //
+ // pIrpRcv is set to NULL while the request is in the
+ // transport. This prevents two completions if an error
+ // occurs
+ //
+ pLowerConn->StateRcv = FILL_IRP ;
+ pConnectEle->pIrpRcv = NULL ;
+ pConnectEle->OffsetFromStart = 0 ;
+
+ //
+ // If the data is available, then just grab it now
+ // (also, if flag is set to TDI_RECEIVE_NO_RESPONSE_EXP, we
+ // need to give hint to the xport, so let xport do the copying)
+ //
+ if ( ( BytesIndicated >= BytesToCopy ) &&
+ ( prcvCont->usFlags == TDI_RECEIVE_NORMAL ) )
+ {
+ CTEMemCopy( prcvCont->ndisBuff.VirtualAddress,
+ pTsdu,
+ BytesToCopy ) ;
+ *BytesTaken += BytesToCopy ;
+ CompletionRcv( prcvCont, STATUS_SUCCESS, BytesToCopy ) ;
+ return STATUS_SUCCESS ;
+ }
+
+ pevrcvbuf->erb_buffer = &prcvCont->ndisBuff ;
+ pevrcvbuf->erb_rtn = CompletionRcv ;
+ pevrcvbuf->erb_size = BytesToCopy ;
+ pevrcvbuf->erb_context = prcvCont ;
+ if (prcvCont->usFlags == TDI_RECEIVE_NO_RESPONSE_EXP)
+ pevrcvbuf->erb_flags = &prcvCont->usFlags ;
+ else
+ pevrcvbuf->erb_flags = &usFlags ;
+
+ DbgPrint("\tTRH: Rcv Dest Buff: 0x") ;
+ DbgPrintNum((ULONG)pevrcvbuf->erb_buffer->VirtualAddress) ; DbgPrint("\r\n") ;
+ return TDI_MORE_PROCESSING ;
+ }
+ else
+ {
+ // the client received some, all or none of the data
+ // For Keep Alives the PduSize is zero so this check
+ // will work correctly and go to the else
+ // Also, if we were attempting to complete a zero-len message
+ // but failed because there was no receive pending then we
+ // must go in PARTIAL_RCV state
+ //
+ if ( (*BytesTaken < PduSize) ||
+ ((status == STATUS_DATA_NOT_ACCEPTED) &&
+ (pConnectEle->TotalPcktLen == 0) &&
+ (pConnectEle->state == NBT_SESSION_UP)) )
+ {
+ //
+ // took some of the data, so keep track of the
+ // rest of the data left here by going to the PARTIALRCV
+ // state.
+ //
+ pLowerConn->StateRcv = PARTIAL_RCV;
+ InsertTailList( &pLowerConn->pDeviceContext->PartialRcvHead,
+ &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = TRUE;
+
+ DbgPrint("TdiReceiveHandler:Switch to Partial Rcv Indicated\r\n") ;
+
+ return STATUS_SUCCESS ;
+ }
+ else
+ {
+ //
+ // Must have taken all of the pdu data, so check for
+ // more data available - if so then reindicate ourselves.
+ // Note that TDI will pickup the bytes taken before any posted
+ // receives are performed.
+ //
+ status = STATUS_SUCCESS ;
+
+ //
+ // The next bytes in the transport will be the
+ // beginning of a Session Header so leave the state
+ // as NORMAL
+ //
+
+ if (BytesAvailable > *BytesTaken)
+ {
+ ULONG ClientBytesTaken = 0 ;
+
+ //
+ // we already added the bytes available the first time
+ // TdiReceiveHandler got called. They will get added
+ // again, so subtract now!
+ //
+ pLowerConn->BytesRcvd -= BytesAvailable;
+
+ status = TdiReceiveHandler( ReceiveEventContext,
+ ConnectionContext,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ &ClientBytesTaken,
+ pTsdu,
+ pevrcvbuf ) ;
+
+ *BytesTaken += ClientBytesTaken ;
+ //
+ // status will be more processing if pervrcvbuf
+ // was setup, else it will be success if
+ // bytes were taken. Note that BytesInXport
+ // is adjusted automatically in the call to
+ // TdiReceiveHandler
+ //
+ }
+ }
+ }
+ return status ;
+
+ case FILL_IRP:
+ {
+ NCB * pNCB = pConnectEle->pIrpRcv ;
+ ULONG BuffAvailable = pNCB->ncb_length - pConnectEle->OffsetFromStart ;
+ ULONG BytesToCopy ;
+
+ // we are still waiting for the rest of the session pdu so
+ // do not call the RcvHandlrNotOs, since we already have the buffer
+ // to put this data in.
+ prcvCont = *((PRCV_CONTEXT*)&pNCB->ncb_reserve) ;
+ ASSERT( prcvCont->Signature = RCVCONT_SIGN ) ;
+
+ //
+ // too much data may have arrived... i.e. part of the next session pdu..
+ // so check and set the receive length accordingly
+ //
+ RemainingPdu = pConnectEle->TotalPcktLen - pConnectEle->BytesRcvd;
+ BytesToCopy = min( RemainingPdu, BuffAvailable ) ;
+ pConnectEle->pIrpRcv = NULL ; // Buffer in the transport
+
+ DbgPrint("\tTRH - FILL_IRP case: Requesting 0x") ;
+ DbgPrintNum( pevrcvbuf->erb_size ) ; DbgPrint("\r\n") ;
+
+ //
+ // Append the new data onto the existing data
+ //
+ ((BYTE*)prcvCont->ndisBuff.VirtualAddress) =
+ pNCB->ncb_buffer + pConnectEle->OffsetFromStart ;
+ prcvCont->ndisBuff.Length =
+ pNCB->ncb_length - pConnectEle->OffsetFromStart ;
+
+ //
+ // If the data is available, then just grab it now
+ //
+ if ( BytesIndicated >= BytesToCopy )
+ {
+ CTEMemCopy( prcvCont->ndisBuff.VirtualAddress,
+ pTsdu,
+ BytesToCopy ) ;
+ *BytesTaken += BytesToCopy ;
+ CompletionRcv( prcvCont, STATUS_SUCCESS, BytesToCopy ) ;
+ return STATUS_SUCCESS ;
+ }
+
+ //
+ // Have to post a buffer since the data isn't available
+ // We also have a new offset for the *next* indication
+ //
+ pevrcvbuf->erb_buffer = &prcvCont->ndisBuff ;
+ pevrcvbuf->erb_rtn = CompletionRcv ;
+ pevrcvbuf->erb_size = BytesToCopy ;
+
+ pevrcvbuf->erb_context = prcvCont ;
+ pevrcvbuf->erb_flags = &usFlags ;
+ ASSERT( pConnectEle->OffsetFromStart <= pNCB->ncb_length ) ;
+
+ DbgPrint("\tTRH: offset, address: 0x") ;
+ DbgPrintNum( pConnectEle->OffsetFromStart ) ; DbgPrint(", 0x") ;
+ DbgPrintNum( (ULONG)prcvCont->ndisBuff.VirtualAddress ) ; DbgPrint("\r\n") ;
+
+ //
+ // State remains in FILL_IRP (only goes to PARTIAL_RCV when no
+ // NCBs are actively receiving and only part of a PDU has been
+ // picked up).
+ //
+ // BytesInXport adjusted in CompletinRcv
+ //
+
+ return TDI_MORE_PROCESSING ;
+ }
+ break ;
+
+ case INDICATE_BUFFER:
+ {
+ DbgPrint("\tTRH: Hit INDICATE_BUFFER state, bytes in hdr: 0x") ;
+ DbgPrintNum( pLowerConn->BytesInHdr ) ;
+ DbgPrint("\r\n") ;
+
+ //
+ // Our context is still setup so adjust things such that
+ // the location to start copying the new data into is right
+ // after the existing data in the session header buffer
+ //
+ prcvCont = (PRCV_CONTEXT) pConnectEle->pIrpRcv ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+ ((BYTE*)prcvCont->ndisBuff.VirtualAddress) =
+ ((BYTE*)&pLowerConn->Hdr) + pLowerConn->BytesInHdr ;
+ prcvCont->ndisBuff.Length =
+ sizeof( pLowerConn->Hdr ) - pLowerConn->BytesInHdr ;
+ pevrcvbuf->erb_size = min( BytesAvailable,
+ sizeof(pLowerConn->Hdr) - pLowerConn->BytesInHdr) ;
+ pevrcvbuf->erb_buffer = &prcvCont->ndisBuff ;
+ pevrcvbuf->erb_rtn = NewSessionCompletionRoutine ;
+ pevrcvbuf->erb_context = prcvCont ;
+ pevrcvbuf->erb_flags = &usFlags ;
+ return TDI_MORE_PROCESSING ;
+ }
+
+ case PARTIAL_RCV:
+ //
+ // If we get indicated in this state, then the client doesn't have
+ // any receive buffers posted and we are in the middle of a
+ // PDU, so just track the new byte count and continue waiting
+ // for the client
+ //
+ DbgPrint("\tTRH: Indicated in Partial_Rcv state\r\n") ;
+ return STATUS_SUCCESS ;
+
+ default:
+ ASSERT( FALSE ) ;
+ break;
+ }
+ }
+ else if ( pLowerConn->State == NBT_SESSION_INBOUND )
+ {
+ status = Inbound(
+ ReceiveEventContext,
+ ConnectionContext,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ pTsdu,
+ &prcvCont
+ );
+ }
+ else if ( pLowerConn->State == NBT_SESSION_OUTBOUND )
+ {
+ status = Outbound(
+ ReceiveEventContext,
+ ConnectionContext,
+ ReceiveFlags,
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ pTsdu,
+ &prcvCont
+ );
+ }
+
+ //
+ // maybe disconnect is going on: reject the data
+ //
+ else
+ {
+ *BytesTaken = BytesAvailable;
+ status = STATUS_SUCCESS;
+ }
+
+ //
+ // Client should *never* pass back a completion buffer (only used by
+ // event handler which isn't supported in a VXD
+ //
+ ASSERT( prcvCont == NULL ) ;
+
+ return status;
+}
+
+//----------------------------------------------------------------------------
+
+TDI_STATUS
+ReceiveAnyHandler ( // Handles NCBRCVANY commands, is
+ IN PVOID ReceiveEventContext, // called after all other receive
+ IN PVOID ConnectionContext, // handlers
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID Data,
+ PVOID * ppBuffer // Pointer to RCV_CONTEXT
+ )
+/*++
+
+Routine Description:
+
+ This routine handles any data not processed by TdiReceiveHandler and
+ RcvHandlrNotOs. It processes ReceiveAny NCBs.
+
+ Note that TdiReceiveHandler calls RcvHandlrNotOs which may call
+ this routine (i.e., this is only called from RcvHandlrNotOs).
+
+Arguments:
+
+--*/
+{
+ TDI_STATUS tdistatus ;
+ tCLIENTELE * pClientEle;
+ PLIST_ENTRY pEntry ;
+ PRCV_CONTEXT prcvCont ;
+
+ DbgPrint("ReceiveAnyHandler Entered \r\n") ;
+ *ppBuffer = NULL ;
+
+ pClientEle = (tCLIENTELE*) ReceiveEventContext ;
+
+ ASSERT( pClientEle->Verify == NBT_VERIFY_CLIENT ) ;
+
+ //
+ // Are there any ReceiveAny NCBs queued for this connection or for
+ // any connection?
+ //
+ if ( !IsListEmpty( &pClientEle->RcvAnyHead ))
+ {
+ pEntry = RemoveHeadList( &pClientEle->RcvAnyHead ) ;
+ DbgPrint("ReceiveAnyHandler - Found Receive Any buffer\r\n") ;
+ }
+ else if ( !IsListEmpty( &pClientEle->pDeviceContext->RcvAnyFromAnyHead ))
+ {
+ pEntry = RemoveHeadList( &pClientEle->pDeviceContext->RcvAnyFromAnyHead ) ;
+ DbgPrint("ReceiveAnyHandler - Found Receive Any from Any buffer\r\n") ;
+ }
+ else
+ return STATUS_SUCCESS ;
+ //
+ // Found one
+ //
+ prcvCont = *ppBuffer = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+ return TDI_MORE_PROCESSING ;
+}
+
+//----------------------------------------------------------------------------
+ VOID
+CompletionRcv(
+ IN PVOID pContext,
+ IN uint tdistatus,
+ IN uint BytesRcvd )
+/*++
+
+Routine Description:
+
+ This routine completes TdiVxdReceive. The NCB is completed or further
+ receives are performed.
+
+Arguments:
+
+ pContext - Pointer to a RCV_CONTEXT structure
+ tdistatus - Completion status
+ BytesRcvd - Bytes copied to the destination buffer
+
+--*/
+{
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnectEle;
+ PRCV_CONTEXT prcvcont = (PRCV_CONTEXT) pContext ;
+
+ DbgPrint("CompletionRcv Entered (BytesRcvd: 0x") ;
+ DbgPrintNum( BytesRcvd ) ; DbgPrint(")\r\n") ;
+
+ ASSERT( prcvcont->Signature == RCVCONT_SIGN ) ;
+ ASSERT( tdistatus ||
+ (!tdistatus && ((prcvcont->pLowerConnId != NULL) &&
+ (prcvcont->pLowerConnId->pUpperConnection != NULL))) ) ;
+
+ //
+ // If an error occurred, bail
+ //
+ if ( tdistatus && tdistatus != TDI_BUFFER_OVERFLOW )
+ {
+ DbgPrint("CompletionRcv: error occurred, status: 0x") ;
+ DbgPrintNum( tdistatus ) ; DbgPrint("\n\r") ;
+
+ //
+ // Make sure the receive IRP doesn't get completed twice if the
+ // connection is still up
+ //
+ if ( prcvcont->pLowerConnId &&
+ prcvcont->pLowerConnId->pUpperConnection )
+ {
+ prcvcont->pLowerConnId->pUpperConnection->pIrpRcv = NULL ;
+ }
+
+ CTEIoComplete( prcvcont->pNCB, tdistatus, 0 ) ;
+ return ;
+ }
+
+ pLowerConn = prcvcont->pLowerConnId ;
+ pConnectEle = pLowerConn->pUpperConnection;
+
+ ASSERT( pConnectEle->Verify == NBT_VERIFY_CONNECTION ) ;
+ pConnectEle->BytesRcvd += BytesRcvd;
+ pConnectEle->OffsetFromStart += BytesRcvd ;
+
+ //
+ // Since we request NCB buffer sizes, we can get more bytes then what
+ // was shown as available. If that happens then we've already consumed
+ // all transport bytes so reset to 0.
+ //
+ if ( pConnectEle->BytesInXport <= BytesRcvd )
+ pConnectEle->BytesInXport = 0 ;
+ else
+ pConnectEle->BytesInXport -= BytesRcvd ;
+
+ //
+ // this case handles when all bytes in a session pdu have arrived...
+ //
+ if (pConnectEle->BytesRcvd == pConnectEle->TotalPcktLen)
+ {
+ //
+ // we have received all of the data for this message
+ // so complete back to the client
+ //
+ DbgPrint("CompletionRcv: PDU Receive done, about to complete client with 0x") ;
+ DbgPrintNum( pConnectEle->OffsetFromStart ) ; DbgPrint(" of total PDU length: 0x") ;
+ DbgPrintNum( pConnectEle->TotalPcktLen ) ; DbgPrint("\r\n") ;
+
+ pConnectEle->pIrpRcv = NULL ;
+
+ //
+ // change the state before completing the ncb because our client can
+ // turn around and post a hangup rightaway (in fact, net send does that!)
+ //
+ pLowerConn->StateRcv = NORMAL;
+ CTEIoComplete( prcvcont->pNCB, STATUS_SUCCESS, pConnectEle->OffsetFromStart ) ;
+
+ //
+ // Freed by CTEIoComplete, make sure we don't use it again
+ //
+ prcvcont = NULL ;
+
+ pConnectEle->OffsetFromStart = 0;
+ pConnectEle->BytesRcvd = 0; // reset for the next session pdu
+ pLowerConn->BytesInHdr = 0 ;
+
+ //
+ // Check if there is still more data in the transport and reindicate
+ // if there is.
+ //
+ if (pConnectEle->BytesInXport)
+ {
+ ULONG BytesTaken = 0 ;
+ DbgPrint("Nbt:ComplRcv - Bytes left in Xport after completing a receive, BytesInXport= 0x") ;
+ DbgPrintNum(pConnectEle->BytesInXport) ;
+ DbgPrint("\r\n") ;
+
+ //
+ // The next thing to do is copy the session header into
+ // pLowerConn->Hdr which this will do.
+ //
+ tdistatus = Reindicate( NULL,
+ pLowerConn,
+ 0, // Rcv flags
+ 0, // Bytes Indicated
+ pConnectEle->BytesInXport, // Bytes Avail
+ &BytesTaken,
+ NULL ) ; // tsdu
+ }
+
+ }
+ else
+ if (pConnectEle->BytesRcvd > pConnectEle->TotalPcktLen)
+ {
+ DbgPrint("CompletionRcv: Too Many Bytes Rcvd!! Rcvd 0x") ;
+ DbgPrintNum( pConnectEle->BytesRcvd ) ;
+ DbgPrint(" Total message length:0x") ;
+ DbgPrintNum( pConnectEle->TotalPcktLen ) ;
+ //DbgPrint(" NCB Buffer size: 0x") ;
+ //DbgPrintNum( prcvcont->pNCB->ncb_length ) ;
+ DbgPrint("\r\n") ;
+ ASSERT(FALSE);
+
+ pConnectEle->pIrpRcv = NULL ;
+ pLowerConn->StateRcv = NORMAL;
+ pConnectEle->BytesRcvd = 0; // reset for the next session pdu
+ pLowerConn->BytesInHdr = 0 ;
+ CTEIoComplete( prcvcont->pNCB, TDI_INVALID_STATE, 0 ) ;
+ }
+ else
+ {
+ ASSERT( prcvcont->pNCB ) ;
+
+ //
+ // Haven't received all of the data for this PDU yet, check to
+ // see how much room the NCB has left in it.
+ //
+ if ( pConnectEle->OffsetFromStart >= prcvcont->pNCB->ncb_length )
+ {
+ // If OffsetFromStart is greater then the buffer size then we
+ // have went beyond the end of the buffer.
+ ASSERT( pConnectEle->OffsetFromStart == prcvcont->pNCB->ncb_length ) ;
+
+ DbgPrint("CompletionRcv: Completed NCB but more data available, Total BytesRecieved: 0x") ;
+ DbgPrintNum( pConnectEle->BytesRcvd ) ;
+ DbgPrint("\r\n Ncb buffer size completed: 0x") ;
+ DbgPrintNum( prcvcont->pNCB->ncb_length ) ;
+ DbgPrint("\r\n") ;
+
+ pConnectEle->pIrpRcv = NULL ;
+ pConnectEle->OffsetFromStart = 0;
+ pLowerConn->StateRcv = PARTIAL_RCV ;
+ InsertTailList( &pLowerConn->pDeviceContext->PartialRcvHead,
+ &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = TRUE;
+
+ //
+ // Done with this NCB, set the status appropriately and hope
+ // the client will submit another NCB to pick up the rest of
+ // the PDU. prcvcont freed by the completion.
+ //
+ CTEIoComplete( prcvcont->pNCB,
+ TDI_BUFFER_OVERFLOW, //translates to: NRC_INCOMP
+ prcvcont->pNCB->ncb_length ) ;
+
+ }
+ else
+ {
+ //
+ // Room still left in the NCB so wait for the transport to
+ // indicate when more data is available (OffsetFromStart has
+ // already been adjusted)
+ //
+ pConnectEle->pIrpRcv = prcvcont->pNCB ;
+ pLowerConn->StateRcv = FILL_IRP ;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+ VOID
+NewSessionCompletionRoutine (
+ IN PVOID pContext,
+ IN uint tdistatus,
+ IN uint BytesReceived
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion of the receive to get the remaining
+ data left in the transport when a session PDU starts in the middle of
+ an indication from the transport. This routine is run as the completion
+ of a recv Irp passed to the transport by NBT, to get the remainder of the
+ data in the transport.
+
+ The routine then calls the normal receive handler, which can either
+ consume the data or pass back an Irp. If an Irp is passed back then
+ the data is copied into that irp in this routine.
+
+ Called when a partial message header is received - puts the data back
+ on the
+
+Arguments:
+
+
+Return Value:
+
+ pConnectionContext - connection context returned to the transport(connection to use)
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ PRCV_CONTEXT prcvCont = pContext ;
+ NTSTATUS status;
+ ULONG BytesTaken = 0;
+ ULONG BytesAvailable ;
+ tCONNECTELE *pConnEle;
+ tLOWERCONNECTION *pLowerConn;
+
+ DbgPrint("NewSessionCompletionRoutine Entered\r\n") ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ pLowerConn = prcvCont->pLowerConnId ;
+ pConnEle = pLowerConn->pUpperConnection ;
+
+ //
+ // If an error occurred just drop the PDU on the floor (though an
+ // error really shouldn't happen)
+ //
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ FreeRcvContext( prcvCont ) ;
+ pLowerConn->StateRcv = NORMAL ;
+ return ;
+ }
+
+ //
+ // Adjust BytesInXport if there were too few bytes for the
+ // session header
+ //
+ if ( BytesReceived > pConnEle->BytesInXport )
+ pConnEle->BytesInXport = BytesReceived ;
+
+ //
+ // there may be data still in the indication buffer,
+ // so add that amount to what we just received. The transport
+ // has already copied the data into the pLowerConn->Hdr so we
+ // just need to update the state.
+ //
+ ASSERT( BytesReceived <= sizeof( pLowerConn->Hdr ) ) ;
+ pLowerConn->BytesInHdr += BytesReceived ;
+
+ //
+ // If we have a full header, process it
+ //
+ if ( pLowerConn->BytesInHdr == sizeof(pLowerConn->Hdr) )
+ {
+ ULONG BytesTaken = 0 ;
+ pLowerConn->StateRcv = NORMAL ; // New session header
+ pLowerConn->BytesInHdr = 0 ;
+ FreeRcvContext( prcvCont ) ;
+
+ //
+ // We indicate just the session header bytes, this will force
+ // the client to post a receive if they are interested in the
+ // rest of the data
+ //
+ status = Reindicate(NULL,
+ pLowerConn,
+ 0, // rcv flags
+ sizeof( pLowerConn->Hdr ),
+ pConnEle->BytesInXport,
+ &BytesTaken,
+ &pLowerConn->Hdr ) ;
+ ASSERT( BytesTaken <= sizeof( pLowerConn->Hdr ) ) ;
+ }
+ else
+ {
+ //
+ // We *still* don't have the full session header so
+ // wait for reindication
+ //
+ return ;
+ }
+}
+//----------------------------------------------------------------------------
+ NTSTATUS
+Reindicate(
+ IN PVOID ReceiveEventContext,
+ IN PVOID ConnectionContext,
+ IN USHORT ReceiveFlags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT PULONG BytesTaken,
+ IN PVOID pTsdu
+ )
+/*++
+
+Routine Description:
+
+ This routine copies data from the Indicate buffer to a 128 byte buffer and
+ then fills this with data from the current indication.
+
+Arguments:
+
+
+Return Value:
+
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS ;
+ tLOWERCONNECTION *pLowerConn;
+ tCONNECTELE *pConnEle;
+ EventRcvBuffer evrcvbuf ;
+
+ DbgPrint("Reindicated Entered\r\n") ;
+ DbgPrint("\tReindicate: Bytes: available, indicated: 0x") ;
+ DbgPrintNum( BytesAvailable ) ; DbgPrint(" 0x") ;
+ DbgPrintNum( BytesIndicated ) ;
+ DbgPrint("\r\n") ;
+ pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
+ pConnEle = pLowerConn->pUpperConnection;
+
+ //
+ // we already added the bytes available the first time TdiReceiveHandler
+ // got called. They will get added again, so subtract now!
+ //
+ pLowerConn->BytesRcvd -= BytesAvailable;
+
+ status = TdiReceiveHandler(NULL,
+ pLowerConn,
+ 0, // rcv flags
+ BytesIndicated,
+ BytesAvailable,
+ BytesTaken,
+ pTsdu,
+ &evrcvbuf );
+
+ //
+ // If a receive context was returned, then post the receive, if bytes
+ // were taken, the state was updated in the receive handler
+ //
+ if ( status == TDI_MORE_PROCESSING )
+ {
+ TDI_REQUEST Request ;
+ PRCV_CONTEXT prcvCont = evrcvbuf.erb_context ;
+ ULONG cbRcvLength = evrcvbuf.erb_size ;
+
+ ASSERT( (evrcvbuf.erb_rtn == CompletionRcv) ||
+ (evrcvbuf.erb_rtn == NewSessionCompletionRoutine))
+ Request.RequestNotifyObject = evrcvbuf.erb_rtn ;
+ Request.RequestContext = prcvCont ;
+ Request.Handle.ConnectionContext = pLowerConn->pFileObject ;
+
+ status = TdiVxdReceive( &Request,
+ &usFlags,
+ &cbRcvLength,
+ &prcvCont->ndisBuff ) ;
+ if ( status != TDI_PENDING )
+ {
+ DbgPrint("Reindicate: Error returned from TdiVxdReceive - 0x") ;
+ DbgPrintNum( status ) ;
+ DbgPrint("\r\n") ;
+ CTEIoComplete( prcvCont->pNCB, status, 0 ) ;
+ }
+ else
+ {
+ status = TDI_SUCCESS ;
+ }
+ }
+
+ return status ;
+}
+
+//----------------------------------------------------------------------------
+
+ TDI_STATUS
+TdiConnectHandler (
+ IN PVOID pConnectEventContext,
+ IN int RemoteAddressLength,
+ IN PVOID pRemoteAddress,
+ IN int UserDataLength,
+ IN PVOID pUserData,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN PVOID * AcceptingID,
+ ConnectEventInfo * pEventInfo //OUT CONNECTION_CONTEXT *pConnectionContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is connect event handler. It is invoked when a request for
+ a connection has been received by the provider. NBT accepts the connection
+ on one of its connections in its LowerConnFree list
+
+ Initially a TCP connection is setup with this port. Then a Session Request
+ packet is sent across the connection to indicate the name of the destination
+ process. This packet is received in the RcvHandler.
+
+Arguments:
+
+ pConnectEventContext - the context passed to the transport when this event was setup
+ RemoteAddressLength - the length of the source address (4 bytes for IP)
+ pRemoteAddress - a ptr to the source address
+ UserDataLength - the number of bytes of user data - includes the session Request hdr
+ pUserData - ptr the the user data passed in
+ OptionsLength - number of options to pass in
+ pOptions - ptr to the options
+
+Return Value:
+
+ pConnectionContext - connection context returned to the transport(connection to use)
+
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ tDEVICECONTEXT * pDeviceContext;
+ tLOWERCONNECTION * pLowerConn ;
+ PTDI_CONNECTION_INFO pConnInfo ;
+
+ DbgPrint("TdiConnectHandler: Entered\r\n") ;
+
+ // convert the context value into the device context record ptr
+ pDeviceContext = (tDEVICECONTEXT *)pConnectEventContext;
+
+ ASSERTMSG("Bad Device context passed to the Connection Event Handler",
+ pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+
+ // call the non-OS specific routine to find a free connection.
+
+ status = ConnectHndlrNotOs(
+ pConnectEventContext,
+ RemoteAddressLength,
+ pRemoteAddress,
+ UserDataLength,
+ pUserData,
+ &pLowerConn );
+
+ if (!NT_SUCCESS(status))
+ {
+ DbgPrint("TdiConnectHandler: NO FREE CONNECTIONS in connect handler\r\n");
+ return STATUS_DATA_NOT_ACCEPTED ;
+ }
+
+ //
+ // Fill in the completion information
+ //
+ pEventInfo->cei_rtn = AcceptCompletionRoutine ;
+ pEventInfo->cei_context = pLowerConn ;
+ pEventInfo->cei_acceptinfo = NULL ;
+ pEventInfo->cei_conninfo = NULL ;
+ *AcceptingID = pLowerConn ; // Connection Context
+
+ return TDI_MORE_PROCESSING ;
+}
+
+//----------------------------------------------------------------------------
+ VOID
+AcceptCompletionRoutine(
+ IN PVOID pContext,
+ IN uint tdistatus,
+ IN uint extra
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion of an Accept to the transport.
+
+Arguments:
+
+
+Return Value:
+
+ NTSTATUS - success or not
+
+--*/
+{
+ tLOWERCONNECTION *pLowerConn;
+
+ DbgPrint("AcceptCompletionRoutine: Entered\r\n") ;
+ pLowerConn = (tLOWERCONNECTION *)pContext;
+
+ if (!NT_SUCCESS(tdistatus) &&
+ (pLowerConn->State == NBT_SESSION_INBOUND))
+ {
+ tDEVICECONTEXT *pDeviceContext;
+ DbgPrint("AcceptCompletionRoutine - Error returned: 0x") ;
+ DbgPrintNum( tdistatus ) ;
+ DbgPrint("\r\n") ;
+
+ // the connection setup failed, so put the lower connection block
+ // back on the free list
+ pLowerConn->State = NBT_IDLE;
+ pDeviceContext = pLowerConn->pDeviceContext;
+
+ //
+ // First remove it from pDeviceContext->LowerConnection
+ //
+ RemoveEntryList( &pLowerConn->Linkage ) ;
+ CTEInterlockedDecrementLong(&pLowerConn->RefCount);
+ InsertHeadList(&pDeviceContext->LowerConnFreeHead,
+ &pLowerConn->Linkage);
+
+ }
+}
+
+//----------------------------------------------------------------------------
+ TDI_STATUS
+TdiDisconnectHandler (
+ PVOID EventContext,
+ PVOID ConnectionContext,
+ ULONG DisconnectDataLength,
+ PVOID pDisconnectData,
+ ULONG DisconnectInformationLength,
+ PVOID pDisconnectInformation,
+ ULONG DisconnectIndicators
+ )
+/*++
+
+Routine Description:
+
+ This routine is called when a session is disconnected from a remote
+ machine.
+
+Arguments:
+
+ IN PVOID EventContext,
+ IN PCONNECTION_CONTEXT ConnectionContext,
+ IN ULONG DisconnectDataLength,
+ IN PVOID DisconnectData,
+ IN ULONG DisconnectInformationLength,
+ IN PVOID DisconnectInformation,
+ IN ULONG DisconnectIndicators
+
+Return Value:
+
+ NTSTATUS - Status of event indicator
+
+--*/
+
+{
+
+ TDI_STATUS status ;
+ tDEVICECONTEXT *pDeviceContext;
+
+ DbgPrint("TdiDisconnectHandler: Entered\r\n") ;
+
+ pDeviceContext = (tDEVICECONTEXT *)EventContext;
+ ASSERTMSG("Bad Device context passed to the Disconnect Event Handler",
+ pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT);
+
+ status = DisconnectHndlrNotOs(
+ EventContext,
+ ConnectionContext,
+ DisconnectDataLength,
+ pDisconnectData,
+ DisconnectInformationLength,
+ pDisconnectInformation,
+ DisconnectIndicators);
+
+ if (!NT_SUCCESS(status))
+ {
+ DbgPrint("NO FREE CONNECTIONS in connect handler\n\r");
+ status = TDI_CONN_REFUSED ; // return(STATUS_DATA_NOT_ACCEPTED);
+ }
+
+ DbgPrint("TdiDisconnectHandler: returning\r\n") ;
+ return status ;
+}
+
+//----------------------------------------------------------------------------
+
+TDI_STATUS
+VxdDisconnectHandler ( // Cleans up Netbios stuff for remote
+ IN PVOID DisconnectEventContext, // disconnects
+ IN PVOID ConnectionContext,
+ IN PVOID DisconnectData,
+ IN ULONG DisconnectInformationLength,
+ IN PVOID pDisconnectInformation,
+ IN ULONG DisconnectIndicators
+ )
+/*++
+
+Routine Description:
+
+ Cleans up open Netbios stuff.
+
+ Note this routine gets called from the NCB hangup completion also.
+
+Arguments:
+
+--*/
+{
+ TDI_STATUS tdistatus ;
+ tCLIENTELE * pClientEle = (tCLIENTELE*) DisconnectEventContext ;
+ tCONNECTELE * pConnEle = (tCONNECTELE*) ConnectionContext ;
+ tDEVICECONTEXT * pDeviceContext = pClientEle->pDeviceContext ;
+ tLOWERCONNECTION * pLowerConn;
+ TDI_REQUEST Request ;
+ NCBERR errNCB ;
+ UCHAR lsn ;
+ BOOL fNotified ;
+
+ DbgPrint("VxdDisconnectHandler Entered \r\n") ;
+ ASSERT( pClientEle->Verify == NBT_VERIFY_CLIENT ) ;
+ ASSERT( (pConnEle->Verify == NBT_VERIFY_CONNECTION) ||
+ (pConnEle->Verify == NBT_VERIFY_CONNECTION_DOWN)) ;
+
+ //
+ // Session is dead, kill off everything
+ //
+
+ if ( errNCB = VxdFindLSN( pDeviceContext,
+ pConnEle,
+ &lsn ))
+ {
+ //
+ // This shouldn't happen but watch for it in case we get in a
+ // weird situation
+ //
+ DbgPrint("VxdDisconnectHandler - Warning: VxdFindLsn failed\r\n") ;
+ }
+
+ REQUIRE( !VxdCompleteSessionNcbs( pDeviceContext,
+ pConnEle )) ;
+
+ pLowerConn = pConnEle->pLowerConnId ;
+ if ( pLowerConn &&
+ (pLowerConn->fOnPartialRcvList == TRUE) &&
+ pLowerConn->StateRcv == PARTIAL_RCV )
+ {
+ RemoveEntryList( &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+ }
+
+ //
+ // The close may free the connection so check if the client has been
+ // notified now.
+ //
+ fNotified = !!(pConnEle->Flags & NB_CLIENT_NOTIFIED) ;
+ Request.Handle.ConnectionContext = pConnEle ;
+ tdistatus = NbtCloseConnection( &Request,
+ NULL,
+ pDeviceContext,
+ NULL ) ;
+ if ( tdistatus )
+ {
+ DbgPrint("VxdDisconnectHandler: NbtCloseConnection returned 0x") ;
+ DbgPrintNum( tdistatus ) ; DbgPrint("\r\n") ;
+ }
+
+ tdistatus = NbtDisassociateAddress( &Request ) ;
+ if ( tdistatus )
+ {
+ DbgPrint("VxdDisconnectHandler: NbtDisassociateAddress returned 0x") ;
+ DbgPrintNum( tdistatus ) ; DbgPrint("\r\n") ;
+ }
+
+ if ( !errNCB && fNotified )
+ {
+ REQUIRE( NBUnregister( pDeviceContext,
+ lsn,
+ NB_SESSION )) ;
+ }
+
+ //
+ // If this name has been deleted, check to see if this is the last session,
+ // if so, delete the name
+ //
+ if ( pClientEle->fDeregistered && !ActiveSessions(pClientEle) )
+ {
+ UCHAR NameNum ;
+ if ( VxdFindNameNum( pDeviceContext, pClientEle->pAddress, &NameNum ))
+ {
+ ASSERT( FALSE ) ;
+ return STATUS_UNSUCCESSFUL ;
+ }
+
+ (void) VxdCleanupAddress( pDeviceContext,
+ NULL,
+ pClientEle,
+ NameNum,
+ TRUE ) ;
+ }
+
+ return STATUS_SUCCESS ;
+}
+
+//----------------------------------------------------------------------------
+
+//
+// This structure is the context that is passed to the datagram completion
+// routine when we want TDI to fill in the NCB's buffer
+//
+typedef struct _RCV_DG_COMP_CONTEXT
+{
+ EventRcvBuffer evrcvbuf ;
+ NCB * pncb ;
+ tCLIENTLIST * pClientList ;
+ NDIS_BUFFER ndisRcvBuf ;
+} RCV_DG_COMP_CONTEXT, *PRCV_DG_COMP_CONTEXT ;
+
+ TDI_STATUS
+TdiRcvDatagramHandler(
+ IN PVOID pDgramEventContext,
+ IN int SourceAddressLength,
+ IN PVOID pSourceAddress,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN UINT Flags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *pBytesTaken,
+ IN PVOID pData,
+ OUT EventRcvBuffer * * ppBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine is the receive datagram event indication handler.
+
+ It is called when an Datagram arrives from the network, it will look for a
+ the address with an appropriate read datagram outstanding or a Datagrm
+ Event handler setup.
+
+Arguments:
+
+ pDgramEventContext - Context provided for this event - pab
+ SourceAddressLength, - length of the src address
+ pSourceAddress, - src address
+ OptionsLength, - options length for the receive
+ pOptions, - options
+ BytesIndicated, - number of bytes this indication
+ BytesAvailable, - number of bytes in complete Tsdu
+ pTsdu - pointer to the datagram
+
+
+Return Value:
+
+ *pBytesTaken - number of bytes used
+ *IoRequestPacket - Receive IRP if MORE_PROCESSING_REQUIRED.
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ TDI_STATUS tdistatus ;
+ tDEVICECONTEXT * pDeviceContext = (tDEVICECONTEXT *)pDgramEventContext;
+ tCLIENTLIST * pClientList = NULL ;
+ NCB * pncb = NULL ;
+
+ //
+ // Tell TDI we don't want anything unless we change our minds down below
+ //
+ *ppBuffer = NULL ;
+
+ ASSERTMSG("NBT:Invalid Device Context passed to DgramRcv Handler!!\n",
+ pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
+
+ // call a non-OS specific routine to decide what to do with the datagrams
+ tdistatus = DgramHndlrNotOs(
+ pDgramEventContext,
+ SourceAddressLength,
+ pSourceAddress,
+ OptionsLength,
+ pOptions,
+ 0, // Receive data flags
+ BytesIndicated,
+ BytesAvailable,
+ pBytesTaken,
+ pData,
+ &pncb,
+ &pClientList ) ;
+ if ( !NT_SUCCESS( tdistatus ) )
+ {
+ // fail the request back to the transport provider since we
+ // could not find a receive buffer or receive handler.
+ return(tdistatus);
+
+ }
+ else
+ {
+ PRCV_DG_COMP_CONTEXT prcvdgContext = NULL ;
+
+ prcvdgContext = CTEAllocMem( sizeof( RCV_DG_COMP_CONTEXT ) ) ;
+ if ( !prcvdgContext )
+ return STATUS_DATA_NOT_ACCEPTED ;
+
+ //
+ // ncb_callname filled in by the NotOs event handler
+ //
+
+ prcvdgContext->evrcvbuf.erb_rtn = CompletionRcvDgram ;
+ prcvdgContext->evrcvbuf.erb_size = BytesAvailable - *pBytesTaken ;
+ prcvdgContext->evrcvbuf.erb_context = prcvdgContext ;
+ prcvdgContext->evrcvbuf.erb_buffer = &prcvdgContext->ndisRcvBuf ;
+ prcvdgContext->pncb = pncb ;
+ prcvdgContext->evrcvbuf.erb_flags = NULL ;
+ prcvdgContext->pClientList = pClientList ;
+ InitNDISBuff( prcvdgContext->evrcvbuf.erb_buffer,
+ pncb->ncb_buffer,
+ pncb->ncb_length,
+ NULL ) ;
+ *ppBuffer = &prcvdgContext->evrcvbuf ;
+ return TDI_MORE_PROCESSING ;
+ }
+
+ //
+ // Transport will complete the processing of the request, we don't
+ // want the datagram.
+ //
+
+ return STATUS_DATA_NOT_ACCEPTED;
+}
+
+//----------------------------------------------------------------------------
+ TDI_STATUS
+TdiRcvNameSrvHandler(
+ IN PVOID pDgramEventContext,
+ IN int SourceAddressLength,
+ IN PVOID pSourceAddress,
+ IN int OptionsLength,
+ IN PVOID pOptions,
+ IN UINT Flags,
+ IN ULONG BytesIndicated,
+ IN ULONG BytesAvailable,
+ OUT ULONG *pBytesTaken,
+ IN PVOID pTsdu,
+ OUT EventRcvBuffer * * ppBuffer
+ )
+/*++
+
+Routine Description:
+
+ This routine is the Name Service datagram event indication handler.
+ It gets all datagrams destined for UDP port 137
+
+
+Arguments:
+
+ pDgramEventContext - Context provided for this event - pab
+ SourceAddressLength, - length of the src address
+ pSourceAddress, - src address
+ OptionsLength, - options length for the receive
+ pOptions, - options
+ BytesIndicated, - number of bytes this indication
+ BytesAvailable, - number of bytes in complete Tsdu
+ pTsdu - pointer to the datagram
+
+
+Return Value:
+
+ *pBytesTaken - number of bytes used
+ *IoRequestPacket - Receive IRP if MORE_PROCESSING_REQUIRED.
+ NTSTATUS - Status of receive operation
+
+--*/
+
+{
+ NTSTATUS status;
+ TDI_STATUS tdistatus ;
+ tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)pDgramEventContext;
+ tNAMEHDR *pNameSrv = (tNAMEHDR *)pTsdu;
+
+ //
+ // No receive buffer
+ //
+ *ppBuffer = NULL ;
+
+ ASSERTMSG("NBT:The Device Context does not have the correct Verification value!!\n",
+ pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
+
+
+ // call a non-OS specific routine to decide what to do with the datagrams
+ status = NameSrvHndlrNotOs(
+ pDeviceContext,
+ pSourceAddress,
+ pNameSrv,
+ BytesIndicated);
+
+ return status ;
+
+ // to keep the compiler from generating warnings...
+ UNREFERENCED_PARAMETER( SourceAddressLength );
+ UNREFERENCED_PARAMETER( BytesIndicated );
+ UNREFERENCED_PARAMETER( BytesAvailable );
+ UNREFERENCED_PARAMETER( pBytesTaken );
+ UNREFERENCED_PARAMETER( pTsdu );
+ UNREFERENCED_PARAMETER( OptionsLength );
+ UNREFERENCED_PARAMETER( pOptions );
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+CompletionRcvDgram(
+ IN PVOID Context,
+ IN UINT tdistatus,
+ IN UINT RcvdSize
+ )
+/*++
+
+Routine Description:
+
+ This routine completes the receive datagram NCB. If multiple clients
+ were listenning then the largest NCB is used as a template and the
+ rest are completed from it.
+
+
+Arguments:
+
+ Context - Pointer to a RCV_DG_COMP_CONTEXT structure set above
+ tdistatus - Completion status
+ Rcvdsize - Number of bytes copied
+
+--*/
+{
+ PRCV_DG_COMP_CONTEXT prcvdgContext = Context ;
+ NCB * pncb = prcvdgContext->pncb ;
+ tCLIENTLIST * pClientList = prcvdgContext->pClientList;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+ NTSTATUS status;
+
+ //
+ // Check to see if our buffer was big enough to get all the data
+ //
+ if ( !tdistatus &&
+ prcvdgContext->evrcvbuf.erb_size > pncb->ncb_length )
+ {
+ tdistatus = STATUS_BUFFER_OVERFLOW ;
+ }
+
+ //
+ // there may be several clients that want to see this datagram so check
+ // the client list to see...
+ //
+ if ( pClientList )
+ {
+ pHead = &pClientList->pAddress->ClientHead;
+ pEntry = pHead->Flink;
+
+#ifdef PROXY_NODE
+ if (!pClientList->fProxy)
+ {
+#endif
+ // *** Client Has posted a receive Buffer, rather than using
+ // *** receive handler - VXD case!
+ // ***
+ while (pEntry != pHead)
+ {
+ tCLIENTELE * pClientEle;
+ NCB * pncbDest ;
+
+ pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
+
+ CTEInterlockedIncrementLong(&pClientEle->RefCount);
+
+ if (pClientEle == pClientList->pClientEle)
+ {
+ // this is the client whose buffer we are using - it is
+ // passed up to the client after all other clients
+ // have been processed.
+ //
+ }
+ else
+ if (!IsListEmpty(&pClientEle->RcvDgramHead))
+ {
+ PLIST_ENTRY pRcvEntry;
+ tRCVELE * pRcvEle;
+ TDI_STATUS tdistatusTmp ;
+ UINT BytesToCopy = 0 ;
+
+ pRcvEntry = RemoveHeadList(&pClientEle->RcvDgramHead);
+ pRcvEle = CONTAINING_RECORD(pRcvEntry,tRCVELE,Linkage);
+ pncbDest = (NCB*) pRcvEle->pIrp ;
+ ASSERT( pncbDest ) ;
+
+ //
+ // Only copy the data and call name if we successfully
+ // completed the datagram
+ //
+ if ( !tdistatus || tdistatus == STATUS_BUFFER_OVERFLOW )
+ {
+ BytesToCopy = min( pncbDest->ncb_length, RcvdSize ) ;
+
+ CTEMemCopy( pncbDest->ncb_buffer,
+ pncb->ncb_buffer,
+ BytesToCopy ) ;
+ CTEMemCopy( pncbDest->ncb_callname,
+ pncb->ncb_callname,
+ NETBIOS_NAME_SIZE ) ;
+
+ if ( pncbDest->ncb_length < RcvdSize ||
+ (pncbDest->ncb_length == RcvdSize &&
+ tdistatus == STATUS_BUFFER_OVERFLOW) )
+ {
+ tdistatusTmp = STATUS_BUFFER_OVERFLOW ;
+ }
+ else
+ tdistatusTmp = STATUS_SUCCESS ;
+ }
+ else
+ {
+ tdistatusTmp = tdistatus ;
+ }
+
+ CTEIoComplete( pncbDest, tdistatusTmp, BytesToCopy ) ;
+
+ // free the receive block
+ CTEMemFree((PVOID)pRcvEle);
+
+ }
+
+ pEntry = pEntry->Flink;
+
+ CTEInterlockedDecrementLong(&pClientEle->RefCount);
+
+
+ } // of while(pEntry != pHead)
+
+ //
+ // The address was referenced in DgramRcvNotOs to be sure
+ // it did not disappear until this dgram rcv was done, which
+ // is now.
+ //
+ NbtDereferenceAddress( pClientList->pAddress ) ;
+
+#ifdef PROXY_NODE
+ }
+ else
+ {
+ //
+ // Call the ProxyDoDgramDist
+ //
+ status = ProxyDoDgramDist(
+ (tDGRAMHDR *)pncb->ncb_buffer,
+ RcvdSize,
+ (tNAMEADDR *)pClientList->pAddress, //NameAddr
+ pClientList->pRemoteAddress //device context
+ );
+
+ }
+#endif
+
+
+ //
+ // Free the buffers allocated
+ //
+ if (!pClientList->fProxy)
+ {
+ CTEMemFree(pClientList->pRemoteAddress);
+ }
+ CTEMemFree(Context);
+ }
+
+ //
+ // Finally complete our template NCB (or only NCB if single receive)
+ //
+ CTEIoComplete( pncb, tdistatus, RcvdSize ) ;
+ CTEMemFree( prcvdgContext ) ;
+
+}
+//----------------------------------------------------------------------------
+ TDI_STATUS
+TdiErrorHandler (
+ IN PVOID Context,
+ IN ULONG Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called on any error indications passed back from the
+ transport. It implements LAN_STATUS_ALERT.
+
+Arguments:
+
+ Context - Supplies the pfcb for the address.
+
+ Status - Supplies the error.
+
+Return Value:
+
+ NTSTATUS - Status of event indication
+
+--*/
+
+{
+ DbgPrint("Nbt: Error Event HAndler hit unexpectedly\r\n");
+ return TDI_INVALID_REQUEST ;
+}
diff --git a/private/ntos/nbt/vxd/tdiout.c b/private/ntos/nbt/vxd/tdiout.c
new file mode 100644
index 000000000..147bcb785
--- /dev/null
+++ b/private/ntos/nbt/vxd/tdiout.c
@@ -0,0 +1,601 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ Tdiout.c
+
+Abstract:
+
+
+ This file represents the TDI interface on the bottom edge of NBT.
+ The procedures herein conform to the TDI I/F spec. and then convert
+ the information to NT specific Irps etc. This implementation can be
+ changed out to run on another OS.
+
+Author:
+
+ Jim Stewart (Jimst) 10-2-92
+
+Revision History:
+
+--*/
+
+#include <nbtprocs.h> // procedure headings
+
+// function prototypes for completion routines used in this file
+VOID
+SendComplete(
+ PVOID pContext,
+ TDI_STATUS tdistatus,
+ UINT cbSentSize
+ );
+VOID
+TcpConnectComplete(
+ PVOID pContext,
+ TDI_STATUS tdistatus,
+ PVOID pv
+ );
+
+VOID DisconnectWaitComplete( PVOID pContext,
+ TDI_STATUS status,
+ ULONG Extra ) ;
+
+void VxdDelayedCallHandler( struct CTEEvent *pEvent, void * pContext ) ;
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiSendDatagram(
+ IN PTDI_REQUEST pRequest,
+ IN PTDI_CONNECTION_INFORMATION pSendDgramInfo,
+ IN ULONG SendLength,
+ OUT PULONG pSentSize,
+ IN tBUFFER * pSendBuffer,
+ IN ULONG SendFlags
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a datagram to the transport
+
+Arguments:
+
+ pSendBuffer - this is really an Mdl in NT land. It must be tacked on
+ the end of the Mdl created for the Nbt datagram header.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ TDI_STATUS tdistatus = TDI_SUCCESS ;
+ PTDI_SEND_CONTEXT psendCont = NULL ;
+
+ if ( !GetSendContext( &psendCont ) )
+ {
+ tdistatus = STATUS_INSUFFICIENT_RESOURCES ;
+ goto ErrorExit ;
+ }
+
+ //
+ // Save away the old completion routine and context and replace them
+ // with new ones. The new completion routines will call the old ones
+ // if they are non-NULL and then free the structure.
+ //
+ psendCont->OldRequestNotifyObject = pRequest->RequestNotifyObject ;
+ psendCont->OldContext = pRequest->RequestContext ;
+ psendCont->NewContext = NULL ;
+ pRequest->RequestContext = psendCont ;
+
+ //
+ // Set the send completion callback
+ //
+ pRequest->RequestNotifyObject = SendComplete;
+
+ InitNDISBuff( &psendCont->ndisHdr,
+ pSendBuffer->pDgramHdr,
+ pSendBuffer->HdrLength,
+ &psendCont->ndisData1 ) ;
+
+ InitNDISBuff( &psendCont->ndisData1,
+ pSendBuffer->pBuffer,
+ pSendBuffer->Length,
+ NULL ) ;
+
+ tdistatus = TdiVxdSendDatagram( pRequest,
+ pSendDgramInfo,
+ SendLength,
+ pSentSize,
+ &psendCont->ndisHdr ) ;
+
+ if ( !NT_SUCCESS( tdistatus ) )
+ goto ErrorExit ;
+
+ return tdistatus ;
+
+ErrorExit:
+
+ DbgPrint("TdiSendDatagram ErrorExit: tdistatus= ") ;
+ DbgPrintNum( tdistatus ) ;
+ DbgPrint("\n\r") ;
+
+ //
+ // Call *our* completion routine which frees memory etc.
+ //
+ if ( psendCont && pRequest->RequestNotifyObject )
+ {
+ ((NBT_COMPLETION)pRequest->RequestNotifyObject)(
+ psendCont,
+ tdistatus,
+ 0 ) ;
+
+ return( STATUS_PENDING );
+ }
+
+ return tdistatus ;
+}
+
+//----------------------------------------------------------------------------
+ VOID
+SendComplete(
+ PVOID pContext,
+ TDI_STATUS tdistatus,
+ UINT cbSentSize
+ )
+/*++
+
+Routine Description:
+
+ This routine handles the completion of a datagram/session send to the
+ transport. It must call the client completion routine and free the TDI_SEND_CONTEXT
+ structure pointed at by pContext.
+
+ Note that this routine may also be called if an error is returned from
+ the send call. This is done to localize cleanup.
+
+Arguments:
+
+ pContext - Pointer to a TDI_SEND_CONTEXT
+ tdistatus - Completion status of the TDI request
+ cbSentSize- Bytes taken by TDI
+
+--*/
+{
+ PTDI_SEND_CONTEXT psendCont = pContext ;
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ DbgPrint("SendComplete: TDI Error reported: 0x") ;
+ DbgPrintNum( tdistatus ) ;
+ DbgPrint("\r\n") ;
+ }
+
+ if ( psendCont )
+ {
+ if ( psendCont->OldRequestNotifyObject )
+ {
+ //
+ // This calls the name server datagram completion routine which
+ // in turn will call CTEIoComplete (VxdIoComplete) which will call
+ // the NCB post routine (and fill out the NCB)
+ //
+ psendCont->OldRequestNotifyObject( psendCont->OldContext,
+ tdistatus,
+ cbSentSize ) ;
+ }
+
+ FreeSendContext( psendCont ) ;
+ }
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiConnect(
+ IN PTDI_REQUEST pRequest,
+ IN ULONG lTimeout,
+ IN PTDI_CONNECTION_INFORMATION pSendInfo,
+ OUT PVOID pIrp //IN PTDI_CONNECTION_INFORMATION pReturnInfo
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a connect request to the tranport provider, to setup
+ a connection to the other side...
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ TDI_STATUS status ;
+ DbgPrint("TdiConnect Entered\n\r") ;
+ status = TdiVxdConnect( pRequest,
+ (PVOID)lTimeout,
+ pSendInfo,
+ NULL ) ; // pReturnInfo) ;
+
+ if ( !NT_SUCCESS( status ) )
+ {
+ DbgPrint("TdiVxdConnect: Returned error " ) ;
+ DbgPrintNum( status ) ;
+ DbgPrint("\n\r") ;
+
+ //
+ // call the completion routine with this status
+ //
+ //
+ (*((NBT_COMPLETION)pRequest->RequestNotifyObject))
+ ((PVOID)pRequest->RequestContext,
+ status,
+ 0L);
+ return STATUS_PENDING;
+ }
+ else
+ {
+ DbgPrint("TdiVxdConnect - Connection ID: 0x") ;
+ DbgPrintNum( (ULONG) pRequest->Handle.ConnectionContext ) ; DbgPrint("\r\n") ;
+ }
+
+ return status ;
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiDisconnect(
+ IN PTDI_REQUEST pRequest,
+ IN PVOID lTimeout,
+ IN ULONG Flags,
+ IN PTDI_CONNECTION_INFORMATION pSendInfo,
+ IN PCTE_IRP pClientIrp,
+ IN BOOLEAN Wait
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a connect request to the tranport provider, to setup
+ a connection to the other side...
+
+Arguments:
+
+ Wait is only used for NT (used in case when deleting address object
+ with open connections, which Vxd doesn't allow due to Netbios spec).
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ TDI_STATUS status ;
+ DbgPrint("TdiDisconnect Entered\n\r") ;
+ DbgPrint("TdiDisconnect - Disconnecting Connection ID: 0x") ;
+ DbgPrintNum( (ULONG) pRequest->Handle.ConnectionContext ) ; DbgPrint("\r\n") ;
+
+ ASSERT( Flags <= 0xffff ) ;
+ status = TdiVxdDisconnect( pRequest,
+ lTimeout,
+ (ushort) Flags,
+ pSendInfo,
+ NULL ) ;
+
+ if ( !NT_SUCCESS( status ) )
+ {
+ DbgPrint("TdiVxdConnect: Returned error " ) ;
+ DbgPrintNum( status ) ;
+ DbgPrint("\n\r") ;
+ }
+
+ return status ;
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+TdiSend(
+ IN PTDI_REQUEST pRequest,
+ IN USHORT sFlags,
+ IN ULONG SendLength,
+ OUT PULONG pSentSize,
+ IN tBUFFER *pBuff,
+ IN ULONG SendFlags
+ )
+/*++
+
+Routine Description:
+
+ This routine sends a packet to the transport on a TCP connection
+
+ If this is a chain send (SendFlags & CHAIN_SEND_FLAG) then pBuff will
+ point to a tBUFFERCHAINSEND (which contains a tBUFFER as its first element).
+
+Arguments:
+
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ TDI_STATUS tdistatus = TDI_SUCCESS ;
+ PTDI_SEND_CONTEXT psendCont = NULL ;
+ tBUFFERCHAINSEND * pSendBuff = (tBUFFERCHAINSEND*) pBuff ;
+ PNDIS_BUFFER pndis2 = NULL ;
+ PNDIS_BUFFER pndis1 = NULL ;
+ DbgPrint("TdiSend Entered - sending 0x") ; DbgPrintNum( SendLength ) ;
+ DbgPrint(" bytes\r\n") ;
+
+ if ( !GetSendContext( &psendCont ))
+ {
+ tdistatus = STATUS_INSUFFICIENT_RESOURCES ;
+ if ( pRequest->RequestNotifyObject )
+ {
+ ((NBT_COMPLETION)pRequest->RequestNotifyObject)(
+ pRequest->RequestContext,
+ tdistatus,
+ 0 ) ;
+ }
+ return tdistatus ;
+ }
+
+ //
+ // Save away the old completion routine and context and replace them
+ // with new ones. The new completion routines will call the old ones
+ // if they are non-NULL and then free the structure.
+ //
+ psendCont->OldRequestNotifyObject = pRequest->RequestNotifyObject ;
+ psendCont->OldContext = pRequest->RequestContext ;
+ psendCont->NewContext = NULL ;
+ pRequest->RequestContext = psendCont ;
+
+ //
+ // Set the send completion callback
+ //
+ pRequest->RequestNotifyObject = SendComplete ;
+
+ //
+ // Build the ndis buffer chain (Header and data)
+ //
+
+ if ( (SendFlags & CHAIN_SEND_FLAG) && pSendBuff->Length2 )
+ {
+ InitNDISBuff( &psendCont->ndisData2,
+ pSendBuff->pBuffer2,
+ pSendBuff->Length2,
+ NULL ) ;
+ pndis2 = &psendCont->ndisData2 ;
+ }
+
+ if ( pSendBuff->tBuff.Length && (SendLength > pSendBuff->tBuff.HdrLength) )
+ {
+ InitNDISBuff( &psendCont->ndisData1,
+ pSendBuff->tBuff.pBuffer,
+ pSendBuff->tBuff.Length,
+ pndis2 ) ;
+ pndis1 = &psendCont->ndisData1 ;
+ }
+
+ InitNDISBuff( &psendCont->ndisHdr,
+ pSendBuff->tBuff.pDgramHdr,
+ pSendBuff->tBuff.HdrLength,
+ pndis1 ) ;
+
+ tdistatus = TdiVxdSend( pRequest,
+ sFlags,
+ SendLength,
+ &psendCont->ndisHdr ) ;
+
+ if ( !NT_SUCCESS( tdistatus ) )
+ goto ErrorExit ;
+ else
+ *pSentSize = SendLength ;
+
+ return tdistatus ;
+
+ErrorExit:
+ //
+ // Call *our* completion routine which frees memory etc.
+ //
+ if ( psendCont && pRequest->RequestNotifyObject )
+ {
+ ((NBT_COMPLETION)pRequest->RequestNotifyObject)(
+ psendCont,
+ tdistatus,
+ 0 ) ;
+ }
+
+ DbgPrint("TdiSend: returning ") ;
+ DbgPrintNum( tdistatus ) ;
+ DbgPrint("\n\r") ;
+ return tdistatus ;
+}
+
+/*******************************************************************
+
+ NAME: VxdScheduleDelayedCall
+
+ SYNOPSIS: Schedules a callback at some later time
+
+ ENTRY: pClientContext - Context to pass callback
+ CallBackRoutine - Routine to call
+
+ RETURNS: STATUS_PENDING if successfully scheduled
+
+ NOTES: This is aliased to CTEQueueForNonDispProcessing.
+
+ The memory for the DCC is freed by the application
+
+ HISTORY:
+ Johnl 2-Sep-1993 Created
+
+********************************************************************/
+
+NTSTATUS VxdScheduleDelayedCall( tDGRAM_SEND_TRACKING * pTracker,
+ PVOID pClientContext,
+ PVOID ClientCompletion,
+ PVOID CallBackRoutine,
+ tDEVICECONTEXT *pDeviceContext )
+{
+ CTELockHandle OldIrq;
+ PDELAYED_CALL_CONTEXT pDCC = CTEAllocMem( sizeof( DELAYED_CALL_CONTEXT )) ;
+
+ if ( !pDCC )
+ return STATUS_INSUFFICIENT_RESOURCES ;
+
+ ASSERT( CallBackRoutine != NULL ) ;
+
+ pDCC->dc_WIC.pTracker = pTracker ;
+ pDCC->dc_WIC.pClientContext = pClientContext ;
+ pDCC->dc_WIC.ClientCompletion = ClientCompletion ;
+ pDCC->dc_Callback = CallBackRoutine ;
+ pDCC->pDeviceContext = pDeviceContext;
+
+ //
+ // put this event on the deviceContext queue if we know the devicecontext
+ // otherwise, on the nbtconfig queue. This allows us to cancel the event
+ // later if we wish to (e.g. adapter goes away in pnp, or lease expires)
+ // if the adapter is marked as going down, don't schedule an event but
+ // execute it synchronously.
+ //
+ if (pDeviceContext)
+ {
+ ASSERT( pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
+
+ if (!pDeviceContext->fDeviceUp)
+ {
+ pDCC->dc_Callback( pDCC ) ;
+
+ DbgPrint("VxdScheduleDelayedCall: device going down,executing now\r\n") ;
+ return( STATUS_SUCCESS );
+ }
+ else
+ {
+ CTESpinLock(pDeviceContext,OldIrq);
+ InsertTailList(&pDeviceContext->DelayedEvents,&pDCC->Linkage);
+ CTESpinFree(pDeviceContext,OldIrq);
+ }
+ }
+ else
+ {
+ CTESpinLock(&NbtConfig,OldIrq);
+ InsertTailList(&NbtConfig.DelayedEvents,&pDCC->Linkage);
+ CTESpinFree(&NbtConfig,OldIrq);
+ }
+
+ CTEInitEvent( &pDCC->dc_event, VxdDelayedCallHandler ) ;
+
+ CTEScheduleEvent( &pDCC->dc_event, pDCC) ;
+
+ return STATUS_PENDING ;
+}
+
+
+void VxdDelayedCallHandler( struct CTEEvent *pEvent, void * pContext )
+{
+ PDELAYED_CALL_CONTEXT pDCC = pContext ;
+ CTELockHandle OldIrq;
+ tDEVICECONTEXT *pDeviceContext;
+
+
+ ASSERT( pDCC != NULL && pDCC->dc_Callback != NULL ) ;
+
+ pDeviceContext = pDCC->pDeviceContext;
+
+ if (pDeviceContext)
+ {
+ ASSERT( pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT );
+ CTESpinLock(pDeviceContext,OldIrq);
+ RemoveEntryList(&pDCC->Linkage);
+ CTESpinFree(pDeviceContext,OldIrq);
+ }
+ else
+ {
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+ RemoveEntryList(&pDCC->Linkage);
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+ }
+
+ pDCC->dc_Callback( pDCC ) ;
+}
+
+
+/*******************************************************************
+
+ NAME: CancelAllDelayedEvents
+
+ SYNOPSIS: Since the device (or the entire vxd!) is going away,
+ cancel all the events that were queued to be scheduled
+ later. If a particular device context is going away (but
+ not the entire system) then execute all those events
+ synchronously.
+
+ ENTRY: pDeviceContext - the device context that's going away
+ NULL if the vxd is getting unloaded
+
+ RETURNS: TRUE if at least one event present and was cancelled
+ FALSE if there were no events queued.
+
+ HISTORY:
+ Koti Jan. 9, 95
+
+********************************************************************/
+
+BOOL
+CancelAllDelayedEvents( tDEVICECONTEXT *pDeviceContext )
+{
+
+ LIST_ENTRY *pHead;
+ LIST_ENTRY *pEntry;
+ PDELAYED_CALL_CONTEXT pDCC;
+ CTELockHandle OldIrq;
+ BOOL fAtLeastOne=FALSE;
+
+
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ if (pDeviceContext)
+ pHead = &pDeviceContext->DelayedEvents;
+ else
+ pHead = &NbtConfig.DelayedEvents;
+
+ pEntry = pHead->Flink;
+
+ while (pEntry != pHead)
+ {
+ pDCC = CONTAINING_RECORD(pEntry,DELAYED_CALL_CONTEXT,Linkage);
+ pEntry = pEntry->Flink;
+
+ RemoveEntryList(&pDCC->Linkage);
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ CTECancelEvent( &pDCC->dc_event );
+
+ //
+ // if only one device context is going away, execute the event now
+ //
+ if (pDeviceContext)
+ {
+ pDCC->dc_Callback( pDCC ) ;
+ }
+ CTESpinLock(&NbtConfig.JointLock,OldIrq);
+
+ fAtLeastOne = TRUE;
+ }
+
+ CTESpinFree(&NbtConfig.JointLock,OldIrq);
+
+ ASSERT( IsListEmpty( pHead ) );
+
+ return( fAtLeastOne );
+}
+
+
diff --git a/private/ntos/nbt/vxd/util.c b/private/ntos/nbt/vxd/util.c
new file mode 100644
index 000000000..b7060052e
--- /dev/null
+++ b/private/ntos/nbt/vxd/util.c
@@ -0,0 +1,192 @@
+//
+//
+// UTIL.C
+//
+// This file contains various utility procedures that are VxD specific. These
+// are called by other VxD specific routines.
+
+#include "nbtprocs.h"
+
+NTSTATUS
+ConvertToIntegerArray(
+ char *pszString,
+ UNALIGNED UCHAR *pArray,
+ int *piNumParts) ;
+
+NTSTATUS
+NbtCreateAddressObjects(
+ IN ULONG IPAddr,
+ IN ULONG IPMask,
+ OUT tDEVICECONTEXT *pDeviceContext);
+
+char * strrchr( const char * pch, int c );
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, NbtCreateAddressObjects)
+#pragma CTEMakePageable(INIT, strrchr)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+#pragma BEGIN_INIT
+
+/*******************************************************************
+
+ NAME: strrchr
+
+ SYNOPSIS: Vxd-land doesn't have a strrchr runtime function so
+ roll our own.
+
+ ENTRY: pch - Pointer to string to search
+ c - Character to search for
+
+ RETURNS: Found position or NULL
+
+ HISTORY:
+ Johnl 31-Aug-1993 Created
+
+********************************************************************/
+
+char * strrchr( const char * pch, int c )
+{
+ char * pchFound = NULL ;
+
+ while ( *pch != '\0' )
+ {
+ if ( *pch == c )
+ pchFound = (char *)pch ;
+
+ //
+ // If double byte do this twice
+ //
+ pch++ ;
+ }
+
+ return pchFound ;
+}
+
+#pragma END_INIT
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NbtCreateAddressObjects(
+ IN ULONG IPAddr,
+ IN ULONG IPMask,
+ OUT tDEVICECONTEXT *pDeviceContext)
+
+/*++
+
+Routine Description:
+
+ This routine gets the ip address and subnet mask out of the registry
+ to calcuate the broadcast address. It then creates the address objects
+ with the transport.
+
+Arguments:
+
+ pucRegistryPath - path to NBT config info in registry
+ pucBindName - name of the service to bind to.
+ pDeviceContext - ptr to the device context... place to store IP addr
+ and Broadcast address permanently
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ NTSTATUS status ;
+ pDeviceContext->IpAddress = IPAddr ;
+ pDeviceContext->SubnetMask = IPMask ;
+
+ CTEPagedCode();
+
+ if ( NbtConfig.UseRegistryBcastAddr )
+ {
+ pDeviceContext->BroadcastAddress = NbtConfig.RegistryBcastAddr ;
+ }
+ else
+ {
+ pDeviceContext->BroadcastAddress = (IPMask & IPAddr) | (~IPMask & -1);
+ }
+
+ // now create the address objects.
+
+ // open the Ip Address for inbound Datagrams.
+ status = NbtTdiOpenAddress(
+ NULL, // &pDeviceContext->hDgram,
+ NULL, // &pDeviceContext->pDgramDeviceObject,
+ &pDeviceContext->pDgramFileObject,
+ pDeviceContext,
+ (USHORT)NBT_DATAGRAM_UDP_PORT,
+ IPAddr, //IP_ANY_ADDRESS,
+ 0); // not a TCP port
+
+ if (NT_SUCCESS(status))
+ {
+ // open the Nameservice UDP port ..
+ status = NbtTdiOpenAddress(
+ NULL, //&pDeviceContext->hNameServer,
+ NULL, //&pDeviceContext->pNameServerDeviceObject,
+ &pDeviceContext->pNameServerFileObject,
+ pDeviceContext,
+ (USHORT)NBT_NAMESERVICE_UDP_PORT,
+ IPAddr,
+ 0); // not a TCP port
+
+ if (NT_SUCCESS(status))
+ {
+ KdPrint(("Nbt: Open Session port %X\n",pDeviceContext));
+ // Open the TCP port for Session Services
+ status = NbtTdiOpenAddress(
+ NULL, //&pDeviceContext->hSession,
+ NULL, //&pDeviceContext->pSessionDeviceObject,
+ &pDeviceContext->pSessionFileObject,
+ pDeviceContext,
+ (USHORT)NBT_SESSION_TCP_PORT,
+ IPAddr,
+ TCP_FLAG | SESSION_FLAG); // TCP port
+
+ if (NT_SUCCESS(status))
+ {
+ //
+ // Open the broadcast address ("*\0\0...") for this device.
+ //
+ TDI_REQUEST tdiRequest ;
+ TDI_ADDRESS_NETBIOS tdiaddr ;
+
+ tdiaddr.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP ;
+ CTEZeroMemory( tdiaddr.NetbiosName, NETBIOS_NAME_SIZE ) ;
+ tdiaddr.NetbiosName[0] = '*' ;
+
+ status = NbtOpenAddress( &tdiRequest,
+ &tdiaddr,
+ pDeviceContext->BroadcastAddress,
+ NULL, // Security descriptor
+ pDeviceContext,
+ NULL ) ;
+ if (NT_SUCCESS(status))
+ {
+ pDeviceContext->hBroadcastAddress = tdiRequest.Handle.AddressHandle ;
+ return(status);
+ }
+
+ DbgPrint("Unable to Open broadcast name\r\n");
+ ASSERT(0);
+ CloseAddress( (HANDLE) pDeviceContext->pSessionFileObject ) ;
+ }
+
+ KdPrint(("Unable to Open Session address with TDI, status = %X\n",status));
+ CloseAddress( (HANDLE) pDeviceContext->pNameServerFileObject ) ;
+
+ }
+ KdPrint(("Unable to Open NameServer port with TDI, status = %X\n",status));
+ CloseAddress( (HANDLE) pDeviceContext->pDgramFileObject ) ;
+ }
+
+ return(status);
+}
+
+
diff --git a/private/ntos/nbt/vxd/vfirst.asm b/private/ntos/nbt/vxd/vfirst.asm
new file mode 100644
index 000000000..c2c777f44
--- /dev/null
+++ b/private/ntos/nbt/vxd/vfirst.asm
@@ -0,0 +1,79 @@
+;*****************************************************************;
+;** Copyright(c) Microsoft Corp., 1990-1992 **;
+;*****************************************************************;
+ page ,132 ; :ts=8
+ TITLE wventry - WinVirtualRdr entrypoint
+
+;*** vfirst - First module in VxDRdr
+;
+
+.386p
+
+;* We don't use the .MODEL statement because it wants to declare
+; _DATA and DGROUP for us; which is a no-no because windows is going to.
+
+
+;* 32 Bit locked code
+_LTEXT SEGMENT DWORD USE32 PUBLIC 'LCODE'
+_LTEXT ENDS
+
+;* Contains 32 Bit locked data
+_LDATA SEGMENT DWORD PUBLIC 'LCODE'
+_LDATA ENDS
+
+_DATA SEGMENT DWORD PUBLIC 'LCODE'
+_DATA ENDS
+
+CONST SEGMENT DWORD PUBLIC 'LCODE'
+CONST ENDS
+
+_BSSbeg SEGMENT DWORD PUBLIC 'LCODE'
+ public _BSSBegin
+_BSSBegin equ this byte
+_BSSbeg ENDS
+
+_BSS SEGMENT DWORD PUBLIC 'LCODE'
+_BSS ENDS
+
+c_common SEGMENT DWORD PUBLIC 'LCODE'
+c_common ENDS
+
+_BSSend SEGMENT DWORD PUBLIC 'LCODE'
+ public _BSSDataEnd
+_BSSDataEnd dd ? ; This gaurantees that we can zero out
+ ; BSS in dwords with out stomping anything
+_BSSend ENDS
+
+;* 32 Bit initialization code
+_ITEXT SEGMENT DWORD USE32 PUBLIC 'ICODE'
+_ITEXT ENDS
+
+;* Contains 32 Bit initialization data
+_IDATA SEGMENT DWORD PUBLIC 'ICODE'
+_IDATA ENDS
+
+;* 32 Bit code
+_TEXT SEGMENT DWORD USE32 PUBLIC 'LCODE'
+_TEXT ENDS
+
+;* Contains 32 Bit data
+;;_DATA SEGMENT DWORD PUBLIC 'PCODE'
+;;_DATA ENDS
+
+;* Real Mode initialization code/data for devices
+_RCODE SEGMENT WORD USE16 PUBLIC 'RCODE'
+_RCODE ENDS
+
+_LGROUP GROUP _LTEXT, _TEXT, _LDATA, _DATA, _BSSbeg, _BSS, c_common, _BSSend
+;;DGROUP GROUP _DATA, CONST, _BSSbeg, _BSS, c_common, _BSSend
+;;DGROUP GROUP _DATA, CONST, _BSSbeg, _BSS, _BSSend
+
+_IGROUP GROUP _ITEXT, _IDATA
+
+;;_PGROUP GROUP _TEXT, _DATA
+;;_PGROUP GROUP _TEXT
+
+;;include segments.inc
+;;include vmm.inc
+
+ end
diff --git a/private/ntos/nbt/vxd/vnbt.rcv b/private/ntos/nbt/vxd/vnbt.rcv
new file mode 100644
index 000000000..aed0293f9
--- /dev/null
+++ b/private/ntos/nbt/vxd/vnbt.rcv
@@ -0,0 +1,15 @@
+/********************************************************************/
+/* VNBT.RCV */
+/* Version control data */
+/********************************************************************/
+#include <version.h>
+#include <netvxd.h>
+
+#define VER_FILETYPE VFT_VXD
+#define VER_FILESUBTYPE VNBT_Device_ID
+#define VER_FILEDESCRIPTION_STR "VNBT VxD Driver"
+#define VER_INTERNALNAME_STR "VNBT"
+#define VER_LEGALCOPYRIGHT_YEARS "1993-1995"
+#define VER_ORIGINALFILENAME_STR "VNBT.386"
+
+#include <common.ver>
diff --git a/private/ntos/nbt/vxd/vnbtd.asm b/private/ntos/nbt/vxd/vnbtd.asm
new file mode 100644
index 000000000..502f362f1
--- /dev/null
+++ b/private/ntos/nbt/vxd/vnbtd.asm
@@ -0,0 +1,993 @@
+;*****************************************************************;
+;** Copyright(c) Microsoft Corp., 1988-1993 **;
+;*****************************************************************;
+;:ts=8
+ TITLE VNBT - Netbios on TCP/IP vxd
+.XLIST
+;*** VNBT -- NetBios on TCP/IP VxD
+;
+; This module contains the device header for the NBT VxD driver.
+;
+ .386p
+ include vmm.inc
+ifdef CHICAGO
+ include ndis.inc
+endif ;; CHICAGO
+ include dosmgr.inc
+ include netvxd.inc
+IFDEF CHICAGO
+ include configmg.inc
+ENDIF
+ include vwin32.inc
+ include vdhcp.inc
+ include debug.inc
+ include vtdi.inc
+
+ Create_VNBT_Service_Table EQU True
+ifdef CHICAGO
+ include vnbt.inc
+else ;; CHICAGO
+ include vnbtd.inc
+endif ;; CHICAGO
+ include vnetbios.inc
+
+ include pageable.inc
+.LIST
+
+Declare_Virtual_Device VNBT,3,0,VNBT_Control,VNBT_Device_ID, \
+ VNBT_Init_Order,VNBT_Api_Handler,VNBT_Api_Handler
+
+
+VxD_DATA_SEG
+VxD_DATA_ENDS
+
+EXTRN __VxdMapSegmentOffsetToFlat:near ; from client.asm
+ifndef CHICAGO
+EXTRN _BSSBegin:DWORD
+EXTRN _BSSDataEnd:DWORD
+endif ;; CHICAGO
+EXTRN _TdiDispatch:DWORD
+
+EXTRN _PostInit_Proc:NEAR
+EXTRN _VxdApiWorker:NEAR
+
+ifndef CHICAGO
+EXTRN _VNBT_NCB_X@20:NEAR
+endif ;; CHICAGO
+
+EXTRN _GetDhcpOption:NEAR
+
+
+VxD_ICODE_SEG
+
+EXTRN _Init:NEAR
+
+MSTCP db 'MSTCP',0 ; Protocol this driver sits on (this will have
+ ; to be changed to get it from an .ini file)
+IFDEF CHICAGO
+bInitialized db 0 ; 0 means not initialized, 1 means we've entered
+ ; the initialization, and 2 means we've left init
+bSuccessInit db 0 ; 0 means initialization failed and all subsequent
+ ; initializations should fail
+ENDIF
+
+NBTSectionName db 'NBT',0 ; Section where parameters are stored
+
+;****************************************************************************
+;** VNBT_Device_Init - VNBT device initialization service.
+;
+; The VNBT device initialization routine. Before calling anything
+; we need to zero out the BSS data area.
+;
+;
+; Entry: (EBX) - System VM Handle
+; (EBP) - System Client Regs structure.
+;
+; Exit: 'CY' clear if we init. successfully.
+; 'CY' set if we've failed.
+;
+BeginProc VNBT_Device_Init
+
+IFDEF CHICAGO
+ ;
+ ; Chicago calls us at both dynamic and static init, so only process
+ ; once
+ ;
+ cmp bInitialized, 2 ; 2 means we've already completed initialization
+ jne Init_Continue
+ clc ; Assume success (is checked below)
+ jmp Init_Exit
+
+Init_Continue:
+ mov bInitialized, 1
+ENDIF
+
+ifndef CHICAGO
+ mov edi, OFFSET32 _BSSBegin
+ mov ecx, OFFSET32 _BSSDataEnd
+ sub ecx, edi
+ shr ecx, 2
+ sub eax, eax
+ cld
+ rep stosd
+endif ;; CHICAGO
+
+ VxDcall VTDI_Get_Version
+ jc Init_Exit ; Get out if VTDI is not installed
+
+ ;
+ ; Get the TDI Vxd dispatch table for "MSTCP" to initialize the TDI
+ ; dispatch table (which will be needed by some of our
+ ; initialization stuff)
+ ;
+ mov eax, OFFSET32 MSTCP
+ push eax
+ VxDcall VTDI_Get_Info
+ add esp, 4
+ cmp eax, 0 ; eax contains NULL or the pointer to the table
+ jne NoError
+
+ Debug_Out "VNBT_Device_Init - VTDI_Get_Info failed!"
+ stc ; Set the carry
+ jmp Init_Exit
+
+NoError:
+ mov _TdiDispatch, eax
+
+ ;
+ ; Initialize the rest of the driver
+ ;
+ call _Init
+ cmp eax, 1 ; Set 'CY' appropriately.
+
+Init_Exit:
+
+IFDEF CHICAGO
+ jc Exit2 ; Failed init, leave bSuccessInit 0
+
+ ;
+ ; If first time through and success, indicate successful initialization
+ ;
+ cmp bInitialized, 1
+ je SetInitFlag
+
+ ;
+ ; We've already been initialized once, was it successful?
+ ;
+ cmp bSuccessInit, 1
+ clc ; test clears the carry so assume success
+ je Exit2
+
+ stc ; Set the carry since we failed init. last time
+ jmp Exit2
+
+SetInitFlag:
+ clc
+ mov bSuccessInit, 1
+
+Exit2:
+ mov bInitialized, 2
+ENDIF
+ ret
+
+
+
+
+EndProc VNBT_Device_Init
+
+
+VxD_ICODE_ENDS
+
+NBT_PAGEABLE_CODE_SEG
+
+ifdef CHICAGO
+_NdisOpenProtocolConfiguration@12 PROC NEAR PUBLIC
+ VxDJmp NdisOpenProtocolConfiguration
+_NdisOpenProtocolConfiguration@12 ENDP
+
+_NdisCloseConfiguration@4 PROC NEAR PUBLIC
+ VxDJmp NdisCloseConfiguration
+_NdisCloseConfiguration@4 ENDP
+
+_NdisReadConfiguration@20 PROC NEAR PUBLIC
+ VxDJmp NdisReadConfiguration
+_NdisReadConfiguration@20 ENDP
+endif ;; CHICAGO
+
+NBT_PAGEABLE_CODE_ENDS
+
+VxD_CODE_SEG
+;****************************************************************************
+;* NCB_Handler
+;
+; Called by VNetBios when NCBs need to be submitted to this driver
+;
+; ENTRY:
+; EBX = NCB being submitted
+;
+; EXIT:
+; AL - return code
+;
+BeginProc NCB_Handler
+
+ ;
+ ; In the master portion of the mif tests, after hitting ctrl-c during
+ ; the attempt to synchronize, a wait add group name NCB is
+ ; submitted with interrupts disabled. The CTE timer event handler
+ ; checks this and schedules an event for when they are re-enabled,
+ ; however since it's a wait NCB, we deadlock in VNBT_NCB_X's block.
+ ;
+ ; Make sure interrupts are enabled.
+ ; BUGBUG - Why were we called with ints disabled?
+ ;
+ ;VMMcall Enable_VM_Ints
+
+ xor eax, eax ; second parm of VNBT_NCB_X is unused when
+
+ifndef CHICAGO
+
+ push eax
+ push eax
+ push eax ; called from here, but is used (e.g.nbtstat)
+ push eax
+ push ebx
+ call _VNBT_NCB_X@20 ; when VNBT_NCB_X is called directly
+
+else ;; CHICAGO
+if 0
+;
+; As of 08-Feb-1996 there is a bug in "vmm.h" where this doesn't
+; work properly, with the result being a misaligned stack pointer.
+;
+ VxDCall VNBT_NCB_X, <ebx, eax, eax, eax, eax>
+else ;; 0
+ push eax
+ push eax
+ push eax
+ push eax
+ push ebx
+ VxDCall VNBT_NCB_X
+endif ;; 0
+endif ;; CHICAGO
+
+ ret
+EndProc NCB_Handler
+
+;****************************************************************************
+;** _DhcpQueryOption - Queries a DHCP option
+;
+; Stub callout to the Dhcp driver
+;
+; Entry: [ESP+4] - IP Address of interest
+; [ESP+8] - DHCP Option number
+; [ESP+12]- Pointer to buffer
+; [ESP+16]- Pointer to buffer size
+;
+;
+
+BeginProc _DhcpQueryOption
+
+ VxdCall VDHCP_Get_Version
+ jnc DQI_Installed
+
+ mov eax, 26 ; DHCP not installed, return invalid param
+ ret
+
+DQI_Installed:
+ push ebp
+ mov ebp,esp
+
+ mov eax, [ebp+20] ; Buff size
+ push eax
+ mov eax, [ebp+16] ; Buff
+ push eax
+ mov eax, [ebp+12] ; Option
+ push eax
+ mov eax, [ebp+8] ; IP Address
+ push eax
+
+ VxdCall VDHCP_Query_Option
+
+ add esp, 16
+
+ pop ebp
+ ret
+
+EndProc _DhcpQueryOption
+
+;****************************************************************************
+;** VNBT_Get_Version - VNBT get version service
+;
+; Called by using devices to make sure the VNBT driver
+; is present. Also returns the version of the VNBT driver.
+;
+; Entry: Nothing
+;
+; Exit: On success, 'CY' is clear, and
+; AH - Major version # of driver.
+; AL - Minor version #
+;
+; On failure, 'CY' is set.
+;
+; Uses: AX
+;
+BeginProc VNBT_Get_Version, SERVICE
+
+ mov ax, VNBT_VERSION
+ clc
+ ret
+
+EndProc VNBT_Get_Version
+
+VxD_CODE_ENDS
+NBT_PAGEABLE_CODE_SEG
+
+;****************************************************************************
+;** VNBT_Device_PostProc - do postprocessing
+;
+; Called by the sytem when all the other stuff (in our case, rdr) is
+; loaded. At this we read the lmhosts file, so that any #INCLUDE with
+; UNC names in it will work.
+; This routine can also be used for other stuff, but for now only lmhosts
+; stuff.
+;
+BeginProc VNBT_Device_PostProc
+
+ call _PostInit_Proc
+ clc
+ ret
+
+EndProc VNBT_Device_PostProc
+
+NBT_PAGEABLE_CODE_ENDS
+VxD_CODE_SEG
+
+;****************************************************************************
+;** VNBT_Control - VNBT device control procedure
+;
+; This procedure dispatches VxD messages to the appropriate handler.
+;
+; Entry: EBX - VM handle
+; (EBP) - Client reg structure
+;
+; Exit: 'NC' is success, 'CY' on failure
+;
+; Uses: All
+;
+BeginProc VNBT_Control
+
+ Control_Dispatch Device_Init, VNBT_Device_Init
+ Control_Dispatch Sys_Dynamic_Device_Init, VNBT_Device_Init
+ Control_Dispatch Sys_Vm_Init, VNBT_Device_PostProc
+IFDEF CHICAGO
+ Control_Dispatch W32_DEVICEIOCONTROL, VNBT_DeviceIoControl
+ENDIF
+
+ clc
+ ret
+
+EndProc VNBT_Control
+
+IFDEF CHICAGO
+;*******************************************************************
+;** VNBT_DeviceIoControl
+;
+; Dispatch routine for VxD services invoked via the Win32
+; DeviceIoControl API.
+;
+; Entry: (ESI) - Points to DIOCParams structure (see VWIN32.H).
+;
+; Exit: (EAX) - Win32 status code, -1 for asynchronous
+; completion.
+; HISTORY:
+; Koti 10-Nov-1994 Created (Modified from wsock version)
+;
+;********************************************************************
+BeginProc VNBT_DeviceIoControl
+
+;;;
+;;; Setup stack frame.
+;;;
+
+ push ebx
+ push esi
+ push edi
+
+ mov eax, [esi.dwIoControlCode]
+ cmp ecx, DIOC_GETVERSION
+ je vdic_doNothing
+ cmp ecx, DIOC_CLOSEHANDLE
+ jne vdic_doSomething
+
+;;;
+;;; For devioctl calls resulting from CreateFile and CloseFile, we don't do
+;;; anything other than return success.
+;;;
+
+vdic_doNothing:
+ xor eax, eax
+ jmp vdic_CommonExit
+
+;;;
+;;; This is an ioctl requiring some work: call our api worker (VxdApiWorker)
+;;;
+
+vdic_doSomething:
+
+;;; Lock the in-buffer.
+
+ mov eax, [esi.lpvInBuffer]
+ or eax, eax
+ jz vdic_outbuf
+
+ cCall __VxdLockBuffer, <eax, [esi.cbInBuffer]>
+ or eax, eax
+ jz vdic_LockFailure
+ mov [esi.lpvInBuffer], eax
+
+vdic_outbuf:
+
+;;; Lock the out-buffer.
+
+ mov eax, [esi.lpvOutBuffer]
+ or eax, eax
+ jz vdic_callApi
+
+ cCall __VxdLockBuffer, <eax, [esi.cbOutBuffer]>
+ or eax, eax
+ jz vdic_LockFailure
+ mov [esi.lpvOutBuffer], eax
+
+vdic_callApi:
+
+ mov eax, 0 ; VxdApiWorker won't trash input buffer
+ push eax
+ mov eax, [esi.cbInBuffer]
+ push eax
+ mov eax, [esi.lpvInBuffer]
+ push eax
+ mov eax, [esi.cbOutBuffer]
+ push eax
+ mov eax, [esi.lpvOutBuffer]
+ push eax
+ mov eax, [esi.dwIoControlCode]
+ push eax
+
+ call _VxdApiWorker
+ add esp, 24
+
+
+;;; Unlock the in-buffer.
+
+ push eax ; save the return code from VxdApiWorker
+ cCall __VxdUnlockBuffer, <[esi.lpvInBuffer], [esi.cbInBuffer]>
+ pop eax
+
+;;; Unlock the out-buffer.
+
+ push eax ; save the return code from VxdApiWorker
+ cCall __VxdUnlockBuffer, <[esi.lpvOutBuffer], [esi.cbOutBuffer]>
+ pop eax
+
+vdic_CommonExit:
+
+ pop edi
+ pop esi
+ pop ebx
+
+ ret
+
+;;;
+;;; Failed to lock parameter structure.
+;;;
+
+vdic_LockFailure:
+
+ Debug_Out "VNBT_DeviceIoControl: cannot lock parameters"
+
+ mov eax, 1784 ; ERROR_INVALID_USER_BUFFER
+ jmp vdic_CommonExit
+
+EndProc VNBT_DeviceIoControl
+
+;*******************************************************************
+;** _ReconfigureDevnode
+;
+; This routine schedules an AppyTime call for the ConfigMgr to
+; call us back when it's ready. It calls our routine VNBT_ConfigCalls
+;
+; Entry: ESP+4 our devnode on the stack
+;
+; Exit: (EAX) - 0 if everything goes well
+; 1 if something goes wrong
+;
+; HISTORY:
+; Koti 15-Dec-1994 Created
+;
+;********************************************************************
+
+BeginProc _ReconfigureDevnode
+
+ push ebp
+ mov ebp, esp
+
+ xor eax, eax
+ push eax ; the flags
+ mov eax, [ebp+8] ; our devnode
+ push eax ; this is our RefData
+ lea eax, VNBT_ConfigCalls ; call back routine
+ push eax
+ VxdCall _CONFIGMG_Call_At_Appy_Time
+ add esp, 12
+ cmp eax, CR_SUCCESS
+ je ReconfigureDevnode_PASS
+ mov eax, 1
+ jmp ReconfigureDevnode_Exit
+
+ReconfigureDevnode_PASS:
+ xor eax, eax
+
+ReconfigureDevnode_Exit:
+IFDEF DBG
+ or eax, eax
+ jz ReconfigureDevnode_GoodJob
+ int 3
+ReconfigureDevnode_GoodJob:
+ENDIF
+ pop ebp
+ ret
+EndProc _ReconfigureDevnode
+
+VxD_CODE_ENDS
+
+NBT_PAGEABLE_CODE_SEG
+
+;*******************************************************************
+;** VNBT_ConfigCalls
+;
+; This routine makes all the calls to the Config Mgr so that our
+; devnode is reconfigured. We first get vredir's devnode, kill it
+; and then reenumerate all the children again. This way vredir
+; gets the msg from ConfigMgr to do whatever it does with a new devnode.
+;
+; If dhcp lease expires and then comes back in, vredir had no way
+; of knowing that lana is usable again: hence this convoluted way.
+;
+; IMPORTANT: if chicago ever changes to add more children to tcp's
+; devnode, this function needs to be modified to enumerate
+; rest of the children and kill them!
+;
+; Entry: (EDX) - our devnode
+;
+; Exit: (EAX) - 0 if everything goes well
+; 1 if something goes wrong
+;
+; HISTORY:
+; Koti 15-Dec-1994 Created
+;
+;********************************************************************
+
+VnbtScratch dd 0
+
+BeginProc VNBT_ConfigCalls
+
+ push ebp
+ mov ebp, esp
+ push esi
+ push edi
+ push ecx
+
+ ;;; First get the first child
+ xor eax, eax
+ push eax ; the flags
+ mov eax, [ebp+8]
+ push eax ; our devnode
+ lea eax, VnbtScratch ; this is where we will receive child node
+ push eax
+ VxdCall _CONFIGMG_Get_Child
+ add esp, 12
+ mov esi, dword ptr [VnbtScratch] ;save the first child in esi
+ mov edi, 0 ; for now, make esi,edi different
+ cmp eax, CR_SUCCESS
+ je ConfigCalls_Label2
+ mov ecx, 1
+ jmp ConfigCalls_Exit
+
+ ;;; Get a sibling of this child
+ConfigCalls_Label2:
+ cmp edi, esi ; did we just kill the first child
+ je ConfigCalls_Label6 ; yes: we are done with all the killings
+ xor eax, eax
+ push eax ; the flags
+ push esi ; the first child
+ lea eax, VnbtScratch ; this is where we will receive sibling
+ push eax
+ VxdCall _CONFIGMG_Get_Sibling
+ add esp, 12
+ mov edi, dword ptr [VnbtScratch] ;edi contains sibling
+ cmp eax, CR_SUCCESS ; found a sibling?
+ je ConfigCalls_Label4 ; yes, go kill it
+ cmp eax, CR_NO_SUCH_DEVNODE ; done with all siblings?
+ je ConfigCalls_Label3 ; yes, go kill the first child
+ mov ecx, 2 ; hmmm: something went wrong
+ jmp ConfigCalls_Exit
+
+ ;;; Done with all the siblings: now kill the first child
+ConfigCalls_Label3:
+ mov edi, esi ; esi=first child, edi=child to kill
+
+ConfigCalls_Label4:
+ ;;; Now, ask ConfigMgr if it's ok to kill our child
+ xor eax, eax
+ push eax ; the flags
+ push edi ; sibling's devnode
+ VxdCall _CONFIGMG_Query_Remove_SubTree
+ add esp, 8
+ cmp eax, CR_SUCCESS ; ok to kill?
+ je ConfigCalls_Label5 ; nope!
+ mov ecx, 4
+ jmp ConfigCalls_Exit
+
+ConfigCalls_Label5:
+ ;;; Now that ConfigMgr approved, kill the child
+ xor eax, eax
+ push eax ; the flags
+ push edi ; sibling's devnode
+ VxdCall _CONFIGMG_Remove_SubTree
+ add esp, 8
+ cmp eax, CR_SUCCESS ; did it die?
+ je ConfigCalls_Label2 ; yes, it did: go kill other siblings
+ mov ecx, 5 ; nope!
+ jmp ConfigCalls_Exit
+
+ConfigCalls_Label6:
+ ;;; Ok, reenumerate our devnode so our children come back to life
+ xor eax, eax
+ push eax ; the flags
+ mov eax, [ebp+8]
+ push eax ; our devnode
+ VxdCall _CONFIGMG_Reenumerate_DevNode
+ add esp, 8
+ cmp eax, CR_SUCCESS ; did it die?
+ je ConfigCalls_Label7 ; nope!
+ mov ecx, 6
+ jmp ConfigCalls_Exit
+
+ConfigCalls_Label7:
+ xor eax, eax
+
+ConfigCalls_Exit:
+IFDEF DBG
+ or eax, eax
+ jz ConfigCalls_GoodJob
+ int 3
+ConfigCalls_GoodJob:
+ENDIF
+ pop ecx
+ pop edi
+ pop esi
+ pop ebp
+ ret
+EndProc VNBT_ConfigCalls
+
+ENDIF
+
+NBT_PAGEABLE_CODE_ENDS
+
+VxD_CODE_SEG
+
+;****************************************************************************
+;** _GetInDosFlag - Retrieves the InDos flag
+;
+;
+; Note: This routine cannot be called at init time (vdosmgr complains
+; the variable not initialized yet)
+;
+; Returns the flag in ax
+;
+
+BeginProc _GetInDosFlag
+
+ push ebx
+
+ VxdCall DOSMGR_Get_IndosPtr
+
+ ;
+ ; Add CB_High_Linear if we are in V86 mode
+ ;
+
+ VMMcall Get_Cur_VM_Handle
+
+ test [ebx.CB_VM_Status], VMStat_PM_Exec
+ jnz GIF_Exit
+
+ add eax, [ebx.CB_High_Linear]
+
+GIF_Exit:
+ movzx eax, word ptr [eax]
+
+ pop ebx
+ ret
+EndProc _GetInDosFlag
+
+;****************************************************************************
+;
+; ULONG
+; RtlCompareMemory (
+; IN PVOID Source1,
+; IN PVOID Source2,
+; IN ULONG Length
+; )
+;
+; Routine Description:
+;
+; This function compares two blocks of memory and returns the number
+; of bytes that compared equal.
+;
+; Arguments:
+;
+; Source1 (ebp+8) - Supplies a pointer to the first block of memory to
+; compare.
+;
+; Source2 (ebp+12) - Supplies a pointer to the second block of memory to
+; compare.
+;
+; Length (ebp+16) - Supplies the Length, in bytes, of the memory to be
+; compared.
+;
+; Return Value:
+;
+; The number of bytes that compared equal is returned as the function
+; value. If all bytes compared equal, then the length of the orginal
+; block of memory is returned.
+;
+;--
+
+RcmSource1 equ [ebp+8]
+RcmSource2 equ [ebp+12]
+RcmLength equ [ebp+16]
+
+public _VxdRtlCompareMemory
+BeginProc _VxdRtlCompareMemory
+
+ push ebp
+ mov ebp,esp
+ push esi
+ push edi
+ cld
+
+ mov esi,RcmSource1 ; (esi) -> first block to compare
+ mov edi,RcmSource2 ; (edi) -> second block to compare
+ mov ecx,RcmLength ; (ecx) = length in bytes
+ and ecx,3 ; (ecx) = length mod 4
+ jz rcm10 ; 0 odd bytes, go do dwords
+
+;
+; Compare "odd" bytes.
+;
+
+ repe cmpsb ; compare odd bytes
+ jnz rcm40 ; mismatch, go report how far we got
+
+;
+; Compare dwords.
+;
+
+rcm10: mov ecx,RcmLength ; (ecx) = length in bytes
+ shr ecx,2 ; (ecx) = length in dwords
+ jz rcm20 ; no dwords, go exit
+
+ repe cmpsd ; compare dwords
+ jnz rcm30 ; mismatch, go find byte
+
+;
+; When we come to rcm20, we matched all the way to the end. Esi
+; points to the byte after the last byte in the block, so Esi - RcmSource1
+; equals the number of bytes that matched
+;
+
+rcm20: sub esi,RcmSource1
+ mov eax,esi
+ pop edi
+ pop esi
+ pop ebp
+ ret
+
+;
+; When we come to rcm30, esi (and edi) points to the dword after the
+; one which caused the mismatch. Back up 1 dword and find the byte.
+; Since we know the dword didn't match, we can assume one byte won't.
+;
+
+rcm30: sub esi,4 ; back up
+ sub edi,4 ; back up
+ mov ecx,5 ; ensure that ecx doesn't count out
+ repe cmpsb ; find mismatch byte
+
+;
+; When we come to rcm40, esi points to the byte after the one that
+; did not match, which is TWO after the last byte that did match.
+;
+
+rcm40: dec esi
+ sub esi,RcmSource1
+ mov eax,esi
+ pop edi
+ pop esi
+ pop ebp
+ ret
+
+EndProc _VxdRtlCompareMemory
+
+;****************************************************************************
+;** VNBT_Api_Handler - handles all request from other vxd's, v86-mode apps
+;
+; This procedure does all the address translations, memory locking etc.
+; and calls the C routine VxdApiWorker() to do the actual work
+;
+; Entry: EBX - VM handle
+; (EBP) - Client reg structure
+;
+; Exit: 'NC' is success, 'CY' on failure
+;
+; Uses: All
+;
+; HISTORY:
+; Koti 16-Jun-1994 Created (Modified from dhcp's version)
+;
+;********************************************************************
+BeginProc VNBT_Api_Handler
+
+
+ push ebp
+ push ebx
+ push esi
+ push edi
+ push edx
+ push ecx
+
+;;; get function op code
+
+ movzx edi, [ebp.Client_CX]
+
+;;;
+;;; Convert the parameter buffer pointers from segmented to flat.
+;;;
+
+;;; first, the output buffer
+
+ movzx eax, [ebp.Client_BX]
+ push eax
+ movzx eax, [ebp.Client_ES]
+ push eax
+ push ebx
+ call __VxdMapSegmentOffsetToFlat
+ add esp, 12
+
+ cmp eax, 0FFFFFFFFh
+ je vnbt_Fault
+
+;;;
+;;; Lock the output buffer.
+;;;
+
+ or eax, eax
+ jz vnbt_DontLock_OutBuf
+
+ movzx ecx, [ebp.Client_DI]
+ cCall __VxdLockBuffer, <eax, ecx>
+
+ or eax, eax
+ jz vnbt_Fault
+
+vnbt_DontLock_OutBuf:
+
+ mov esi, eax
+
+;;; now, convert and lock the input buffer
+
+ movzx eax, [ebp.Client_AX]
+ push eax
+ movzx eax, [ebp.Client_DX]
+ push eax
+ push ebx
+ call __VxdMapSegmentOffsetToFlat
+ add esp, 12
+
+ cmp eax, 0FFFFFFFFh
+ je vnbt_Fault
+
+ or eax, eax
+ jz vnbt_DontLock
+
+ movzx ebx, [ebp.Client_SI]
+ cCall __VxdLockBuffer, <eax, ebx> ; this preserves esi
+
+ or eax, eax
+ jz vnbt_Fault
+
+vnbt_DontLock:
+
+ mov edx, eax
+
+;;; call worker routine
+;;; edi - opcode
+;;; esi - OutBuffer pointer
+;;; ecx - OutBuffer length
+;;; edx - InBuffer pointer
+;;; ebx - InBuffer length
+
+;
+; RLF 05/30/94 - __VxdLockBuffer destroys contents of cx - reload
+;
+
+ push esi ; save OutBuffer addr
+ push edx ; save InBuffer addr
+
+ mov eax, 1 ; VxdApiWorker will trash input buffer
+ push eax
+ movzx ecx, [ebp.Client_DI]
+ movzx ebx, [ebp.Client_SI]
+ push ebx
+ push edx
+ push ecx
+ push esi
+ push edi
+
+ call _VxdApiWorker
+ add esp, 24
+
+ pop edx ; restore InBuffer addr
+ pop esi ; restore OutBuffer addr
+
+ mov [ebp.Client_AX], ax
+
+;;;
+;;; Unlock the parameter buffer.
+;;;
+
+ or esi, esi
+ jz vnbt_DontUnLock_OutBuf
+
+ push edx ; save InBuffer addr
+ movzx ecx, [ebp.Client_DI]
+ cCall __VxdUnlockBuffer <esi, ecx>
+ pop edx ; restore InBuffer addr
+vnbt_DontUnLock_OutBuf:
+
+ or edx, edx
+ jz vnbt_DontUnLock
+
+ movzx ebx, [ebp.Client_SI]
+ cCall __VxdUnlockBuffer <edx, ebx>
+
+vnbt_DontUnLock:
+
+vnbt_CommonExit:
+
+;;; Restore stack fame
+ pop ecx
+ pop edx
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+;;;
+;;; Either failed to map a segmented pointer to flat or failed
+;;; to lock the parameter buffer.
+;;;
+
+vnbt_Fault:
+
+ cmp eax, 0FFFFFFFFh
+ mov [ebp.Client_AX], ax
+ jmp vnbt_CommonExit
+
+
+EndProc VNBT_Api_Handler
+
+VxD_CODE_ENDS
+END
+
diff --git a/private/ntos/nbt/vxd/vnbtd.def b/private/ntos/nbt/vxd/vnbtd.def
new file mode 100644
index 000000000..2133cc04d
--- /dev/null
+++ b/private/ntos/nbt/vxd/vnbtd.def
@@ -0,0 +1,21 @@
+VXD VNBT DYNAMIC
+
+DESCRIPTION 'TCP/IP on NetBIOS (NBT) driver'
+
+EXETYPE DEV386
+
+SEGMENTS
+ _LTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
+ _TEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE
+ _LDATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
+ _DATA CLASS 'LCODE' PRELOAD NONDISCARDABLE
+ CONST CLASS 'LCODE' PRELOAD NONDISCARDABLE
+ _BSSbeg CLASS 'LCODE' PRELOAD NONDISCARDABLE
+ _BSS CLASS 'LCODE' PRELOAD NONDISCARDABLE
+ c_common CLASS 'LCODE' PRELOAD NONDISCARDABLE
+ _BSSend CLASS 'LCODE' PRELOAD NONDISCARDABLE
+ _ITEXT CLASS 'ICODE' DISCARDABLE
+ _IDATA CLASS 'ICODE' DISCARDABLE
+
+EXPORTS
+ VNBT_DDB @1
diff --git a/private/ntos/nbt/vxd/vnbtd.inc b/private/ntos/nbt/vxd/vnbtd.inc
new file mode 100644
index 000000000..a8aa28830
--- /dev/null
+++ b/private/ntos/nbt/vxd/vnbtd.inc
@@ -0,0 +1,18 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1992
+;
+; Title: VNBT.INC - Virtual NBT Device Service Declarations
+;
+; Version: 1.01
+;
+
+
+VNBT_VERSION equ 0101h
+
+Begin_Service_Table VNBT
+
+VNBT_Service VNBT_Get_Version, LOCAL
+
+End_Service_Table VNBT
+
diff --git a/private/ntos/nbt/vxd/vnbtd.mk b/private/ntos/nbt/vxd/vnbtd.mk
new file mode 100644
index 000000000..6aeb2810a
--- /dev/null
+++ b/private/ntos/nbt/vxd/vnbtd.mk
@@ -0,0 +1,318 @@
+#
+#:ts=4
+#
+
+ROOTDIR=..
+!include rules.mk
+
+#
+# TCP should point to the root of Henry's TCP vxd tree
+#
+#
+
+!ifndef CHICAGO
+#CHICAGO=$(DEFDRIVE)$(DEFDIR)\chicago
+CHICAGO=k:\
+!endif
+
+VNBTSRC=$(ROOTDIR)\vxd
+COMVNBTOBJD=$(COMDEBOBJ)
+COMVNBTOBJ=$(COMNODEBOBJ)
+
+NBTLIBS=$(ROOTDIR)\nbt\nodebug\nbt.lib
+NBTDLIBS=$(ROOTDIR)\nbt\debug\nbt.lib
+
+NDISLIBR=$(TCP)\ndis31\retail\libndis.lib
+NDISLIBD=$(TCP)\ndis31\debug\libndis.lib
+
+#
+# Hack to get around include path limits when trying to get to the DHCP
+# header files.
+#
+IMPORT_HEADERS=$(BLT)\dhcpinfo.h $(BLT)\vdhcp.inc
+
+$(BLT)\dhcpinfo.h: $(DHCP)\dhcpinfo.h
+ copy $(DHCP)\dhcpinfo.h $(BLT)
+
+$(BLT)\vdhcp.inc: $(TCP)\inc\vdhcp.inc
+ copy $(TCP)\inc\vdhcp.inc $(BLT)
+
+
+
+CHIVNBTOBJD =$(CNODEBOBJ)
+CHIDVNBTOBJD=$(CDEBOBJ)
+SNOVNBTOBJD =$(SNODEBOBJ)
+SNODVNBTOBJD=$(SDEBOBJ)
+
+RC=$(CHICAGO)\dev\sdk\bin\rc
+ADRC2VXD=adrc2vxd
+
+VNBTOBJS=\
+ $(SNODEBOBJ)\cxport.obj \
+ $(SNODEBOBJ)\vfirst.obj \
+ $(SNODEBOBJ)\vnbtd.obj \
+ $(SNODEBOBJ)\client.obj \
+ $(SNODEBOBJ)\fileio.obj \
+ $(SNODEBOBJ)\cinit.obj \
+ $(SNODEBOBJ)\ncb.obj \
+ $(SNODEBOBJ)\vxdisol.obj \
+ $(SNODEBOBJ)\tdicnct.obj \
+ $(SNODEBOBJ)\tdiout.obj \
+ $(SNODEBOBJ)\util.obj \
+ $(SNODEBOBJ)\tdiaddr.obj \
+ $(SNODEBOBJ)\tdihndlr.obj \
+ $(SNODEBOBJ)\ctimer.obj \
+ $(SNODEBOBJ)\nbtinfo.obj \
+ $(SNODEBOBJ)\vxddebug.obj \
+ $(SNODEBOBJ)\chic.obj \
+ $(SNODEBOBJ)\chicasm.obj \
+ $(SNODEBOBJ)\wfw.obj \
+ $(SNODEBOBJ)\wfwasm.obj
+
+VXDFILEOBJ=$(SNODEBOBJ)\vxdfile.obj
+CVXDFILEOBJ=$(SNODEBOBJ)\cvxdfile.obj
+
+SNOVNBTOBJS=$(VNBTOBJS) $(VXDFILEOBJ)
+SNODVNBTOBJS=$(SNOVNBTOBJS:nodebug=debug)
+
+
+SNOVNBTOBJS_C=$(VNBTOBJS) $(CVXDFILEOBJ)
+CHIVNBTOBJS=$(SNOVNBTOBJS_C:snowball=chicago)
+CHIDVNBTOBJS=$(CHIVNBTOBJS:nodebug=debug)
+
+VTSF1=$(VNBTSRC:\=/)
+VTSF=$(VTSF1:.=\.)
+CHICAGOF=$(CHICAGO:\=/)
+TCPF=$(TCP:\=/)
+
+VNBTBINCS= $(BLT)\netvxd.inc $(BLT)\cxport.inc $(TCP)\inc\vtdi.inc
+
+VNBTAFLAGS = -DIS_32 -nologo -W2 -Zd -Cp -Cx -DMASM6 -DVMMSYS
+
+SNOVNBTAFLAGS= $(VNBTAFLAGS) -DWIN31COMPAT
+SNOVNBTAINC=$(VNBTSRC);$(NBT)\vxd;$(INC);$(BLT);$(WIN32INC);$(COMMON)\inc;$(NDIS3INC);$(IMPORT)\wininc;$(TCP)\inc;$(TCP)\blt
+
+CHIVNBTAFLAGS= $(VNBTAFLAGS) -DCHICAGO
+CHIVNBTAINC=$(VNBTSRC);$(NBT)\vxd;$(CHICAGO)\dev\ddk\inc;$(CHICAGO)\dev\inc;$(INC);$(BLT);$(WIN32INC);$(COMMON)\inc;$(NDIS3INC);$(IMPORT)\wininc;$(TCP)\inc;$(TCP)\blt
+
+VNBTCFLAGS = -c -DVXD -Zp1l -Owx -nologo -D_X86_=1 -Di386=1 -DDEVL=1 -DPROXY_NODE
+
+#
+# Note that if netvxd.inc in tcp\blt differs from tcp\blt\snowcomm in
+# something vnbt uses, we'll need different assember targets with different
+# include path statements
+#
+VNBTAINC=$(VNBTSRC);$(INC);$(BLT);$(NDIS3INC);$(WIN32INC);$(COMMON)\inc;$(IMPORT)\wininc;$(TCP)\inc;$(TCP)\blt
+#SVNBTAINC=$(VNBTAINC);$(TCP)\blt\snowcomm
+#CVNBTAINC=$(VNBTAINC);$(TCP)\blt
+
+SNOVNBTCFLAGS= $(VNBTCFLAGS)
+SNOVNBTCINC=.;..\inc;$(TCP)\h;..\..\inc;$(BASEDIR)\private\inc;$(BASEDIR)\public\sdk\inc;$(BASEDIR)\public\sdk\inc\crt;$(NDIS3INC);$(WIN32INC);$(IMPORT)\c8386\inc32;$(IMPORT)\common\h;$(IMPORT)\wininc;$(BLT)
+
+CHIVNBTCFLAGS= $(VNBTCFLAGS) -DCHICAGO
+CHIVNBTCINC=.;..\inc;$(TCP)\h;..\..\inc;$(BASEDIR)\private\inc;$(BASEDIR)\public\sdk\inc;$(BASEDIR)\public\sdk\inc\crt;$(CHICAGO)\dev\ddk\inc;$(CHICAGO)\dev\inc;$(NDIS3INC);$(WIN32INC);$(IMPORT)\c8386\inc32;$(IMPORT)\common\h;$(IMPORT)\wininc;$(BLT)
+
+#
+# \Common rules
+#
+# Note that there currently isn't any platform specific .obj that needs to
+# be built. If a file does become platform specific, then copy the following
+# four rules and replace COM*OBJ with C*OBJ and/or S*OBJ
+
+{$(VNBTSRC)}.asm{$(CHIVNBTOBJD)}.obj:
+ set INCLUDE=$(CHIVNBTAINC)
+ set ML=$(CHIVNBTAFLAGS)
+ $(ASM) -c -Fo$(CHIVNBTOBJD)\$(@B).obj $(VNBTSRC)\$(@B).asm
+
+{$(VNBTSRC)}.asm{$(CHIDVNBTOBJD)}.obj:
+ set INCLUDE=$(CHIVNBTAINC)
+ set ML=$(CHIVNBTAFLAGS) -DDEBUG
+ $(ASM) -c -Fo$(CHIDVNBTOBJD)\$(@B).obj $(VNBTSRC)\$(@B).asm
+
+{$(VNBTSRC)}.asm{$(SNOVNBTOBJD)}.obj:
+ set INCLUDE=$(SNOVNBTAINC)
+ set ML=$(SNOVNBTAFLAGS)
+ $(ASM) -c -Fo$(SNOVNBTOBJD)\$(@B).obj $(VNBTSRC)\$(@B).asm
+
+{$(VNBTSRC)}.asm{$(SNODVNBTOBJD)}.obj:
+ set INCLUDE=$(SNOVNBTAINC)
+ set ML=$(SNOVNBTAFLAGS) -DDEBUG
+ $(ASM) -c -Fo$(SNODVNBTOBJD)\$(@B).obj $(VNBTSRC)\$(@B).asm
+
+{$(VNBTSRC)}.c{$(CHIVNBTOBJD)}.obj:
+ set INCLUDE=$(CHIVNBTCINC)
+ set CL=$(CHIVNBTCFLAGS)
+ $(CL386) -Fo$(CHIVNBTOBJD)\$(@B).obj $(VNBTSRC)\$(@B).c
+
+{$(VNBTSRC)}.c{$(CHIDVNBTOBJD)}.obj:
+ set INCLUDE=$(CHIVNBTCINC)
+ set CL=$(CHIVNBTCFLAGS) -DDEBUG -DDBG=1 -Oy- -Zd
+ $(CL386) -Fo$(CHIDVNBTOBJD)\$(@B).obj $(VNBTSRC)\$(@B).c
+
+{$(VNBTSRC)}.c{$(SNOVNBTOBJD)}.obj:
+ set INCLUDE=$(SNOVNBTCINC)
+ set CL=$(SNOVNBTCFLAGS)
+ $(CL386) -Fo$(SNOVNBTOBJD)\$(@B).obj $(VNBTSRC)\$(@B).c
+
+{$(VNBTSRC)}.c{$(SNODVNBTOBJD)}.obj:
+ set INCLUDE=$(SNOVNBTCINC)
+ set CL=$(SNOVNBTCFLAGS) -DDEBUG -DDBG=1 -Oy- -Zd
+ $(CL386) -Fo$(SNODVNBTOBJD)\$(@B).obj $(VNBTSRC)\$(@B).c
+
+{$(VNBTSRC)}.h{$(BLT)}.inc:
+ $(SED) -f $(SHTOINC) <$< >$(BLT)\$(@B).inc
+
+$(CNODEBOBJ)\cxport.obj: $(TCP)\bin\chicago\nodebug\cxport.obj
+ copy $(TCP)\bin\chicago\nodebug\cxport.obj $(CNODEBOBJ)
+
+$(CDEBOBJ)\cxport.obj: $(TCP)\bin\chicago\debug\cxport.obj
+ copy $(TCP)\bin\chicago\debug\cxport.obj $(CDEBOBJ)
+
+$(SNODEBOBJ)\cxport.obj: $(TCP)\bin\snowball\nodebug\cxport.obj
+ copy $(TCP)\bin\snowball\nodebug\cxport.obj $(SNODEBOBJ)
+
+$(SDEBOBJ)\cxport.obj: $(TCP)\bin\snowball\debug\cxport.obj
+ copy $(TCP)\bin\snowball\debug\cxport.obj $(SDEBOBJ)
+
+svnbt: $(SNODEBBIN)\VNBT.386 $(TCP)\bin\snowball\nodebug\cxport.obj
+
+svnbtd: $(SDEBBIN)\VNBT.386 $(TCP)\bin\snowball\debug\cxport.obj
+
+cvnbt: $(CNODEBBIN)\VNBT.386 $(TCP)\bin\chicago\nodebug\cxport.obj
+
+cvnbtd: $(CDEBBIN)\VNBT.386 $(TCP)\bin\chicago\debug\cxport.obj
+
+clean:
+ -del $(SNODEBBIN)\*.obj
+ -del $(SNODEBBIN)\*.sym
+ -del $(SNODEBBIN)\*.386
+ -del $(SNODEBBIN)\*.map
+ -del $(SDEBBIN)\*.obj
+ -del $(SDEBBIN)\*.sym
+ -del $(SDEBBIN)\*.386
+ -del $(SDEBBIN)\*.map
+
+ -del $(CNODEBBIN)\*.obj
+ -del $(CNODEBBIN)\*.sym
+ -del $(CNODEBBIN)\*.386
+ -del $(CNODEBBIN)\*.map
+ -del $(CDEBBIN)\*.obj
+ -del $(CDEBBIN)\*.sym
+ -del $(CDEBBIN)\*.386
+ -del $(CDEBBIN)\*.map
+
+cleanlink:
+ -del $(SNODEBBIN)\*.obj
+ -del $(SNODEBBIN)\*.sym
+ -del $(SNODEBBIN)\*.386
+ -del $(SNODEBBIN)\*.map
+ -del $(SDEBBIN)\*.obj
+ -del $(SDEBBIN)\*.sym
+ -del $(SDEBBIN)\*.386
+ -del $(SDEBBIN)\*.map
+
+ -del $(CNODEBBIN)\*.obj
+ -del $(CNODEBBIN)\*.sym
+ -del $(CNODEBBIN)\*.386
+ -del $(CNODEBBIN)\*.map
+ -del $(CDEBBIN)\*.obj
+ -del $(CDEBBIN)\*.sym
+ -del $(CDEBBIN)\*.386
+ -del $(CDEBBIN)\*.map
+
+#----------------------------------------------------------------------
+
+$(SNODEBBIN)\VNBT.386: $(SNOVNBTOBJS) $(NBTLIBS) $(IMPORT_HEADERS)
+ $(LINK386) @<<
+$(SNOVNBTOBJS: =+
+) /NOD /NOI /MAP /NOLOGO
+$(SNODEBBIN)\VNBT.386
+$(SNODEBBIN)\VNBT.map
+$(NBTLIBS)
+$(VNBTSRC)\VNBTD.def
+<<
+ $(MAPSYM386) $(SNODEBBIN)\VNBT
+ -del $(SNODEBBIN)\VNBT.sym
+ $(MV) VNBT.sym $(SNODEBBIN)
+
+#----------------------------------------------------------------------
+
+$(SDEBBIN)\VNBT.386: $(SNODVNBTOBJS) $(NBTDLIBS) $(IMPORT_HEADERS)
+ $(LINK386) @<<
+$(SNODVNBTOBJS: =+
+) /NOD /NOI /MAP /NOLOGO
+$(SDEBBIN)\VNBT.386
+$(SDEBBIN)\VNBT.map
+$(NBTDLIBS)
+$(VNBTSRC)\VNBTD.def
+<<
+ $(MAPSYM386) $(SDEBBIN)\VNBT
+ -del $(SDEBBIN)\VNBT.sym
+ $(MV) VNBT.sym $(SDEBBIN)
+
+#----------------------------------------------------------------------
+
+$(CNODEBBIN)\VNBT.386: $(CHIVNBTOBJS) $(NBTLIBS) $(IMPORT_HEADERS)
+ $(LINK386) @<<
+$(CHIVNBTOBJS: =+
+) /NOD /NOI /MAP /NOLOGO
+$(CNODEBBIN)\VNBT.386
+$(CNODEBBIN)\VNBT.map
+$(NBTLIBS) $(NDISLIBR)
+$(VNBTSRC)\VNBTD.def
+<<
+ $(RC) -i $(CHICAGO)\dev\ddk\inc -i $(CHICAGO)\dev\inc -r VNBT.RCV
+ $(ADRC2VXD) $(CNODEBBIN)\VNBT.386 VNBT.RES
+ $(MAPSYM386) $(CNODEBBIN)\VNBT
+ -del $(CNODEBBIN)\VNBT.sym
+ $(MV) VNBT.sym $(CNODEBBIN)
+
+#----------------------------------------------------------------------
+
+$(CDEBBIN)\VNBT.386: $(CHIDVNBTOBJS) $(NBTDLIBS) $(IMPORT_HEADERS)
+ $(LINK386) @<<
+$(CHIDVNBTOBJS: =+
+) /NOD /NOI /MAP /NOLOGO
+$(CDEBBIN)\VNBT.386
+$(CDEBBIN)\VNBT.map
+$(NBTDLIBS) $(NDISLIBD)
+$(VNBTSRC)\VNBTD.def
+<<
+ $(RC) -i $(CHICAGO)\dev\ddk\inc -i $(CHICAGO)\dev\inc -r VNBT.RCV
+ $(ADRC2VXD) $(CDEBBIN)\VNBT.386 VNBT.RES
+ $(MAPSYM386) $(CDEBBIN)\VNBT
+ -del $(CDEBBIN)\VNBT.sym
+ $(MV) VNBT.sym $(CDEBBIN)
+
+
+$(BLT)\netvxd.inc: $(COMMON)\h\netvxd.h
+$(BLT)\cxport.inc: $(TCP)\h\cxport.h
+
+depend: VNBTdep
+
+VNBTdep: $(VNBTBINCS)
+ -copy $(VNBTSRC)\depend.mk $(VNBTSRC)\depend.old
+ echo #******************************************************************** > $(VNBTSRC)\depend.mk
+ echo #** Copyright(c) Microsoft Corp., 1993 ** >> $(VNBTSRC)\depend.mk
+ echo #******************************************************************** >> $(VNBTSRC)\depend.mk
+ set INCLUDE=$(SNOVNBTAINC)
+ -$(INCLUDES) -i -e -S$$(SNOVNBTOBJD) -S$$(SNODVNBTOBJD) -sobj $(VNBTSRC)\*.asm >> $(VNBTSRC)\depend.mk
+ set INCLUDE=$(CHIVNBTAINC)
+ -$(INCLUDES) -i -e -S$$(CHIVNBTOBJD) -S$$(CHIDVNBTOBJD) -sobj $(VNBTSRC)\*.asm >> $(VNBTSRC)\depend.mk
+ set INCLUDE=$(SNOVNBTCINC)
+ -$(INCLUDES) -i -e -S$$(SNOVNBTOBJD) -S$$(SNODVNBTOBJD) -sobj $(VNBTSRC)\*.c >> $(VNBTSRC)\depend.mk
+ set INCLUDE=$(CHIVNBTCINC)
+ -$(INCLUDES) -i -e -S$$(CHIVNBTOBJD) -S$$(CHIDVNBTOBJD) -sobj $(VNBTSRC)\*.c >> $(VNBTSRC)\depend.mk
+ $(SED) -e s`$(IMPF)`$$(IMPORT)`g <$(VNBTSRC)\depend.mk > $(VNBTSRC)\depend.tmp
+ $(SED) -e s`$(CMNF)`$$(COMMON)`g <$(VNBTSRC)\depend.tmp > $(VNBTSRC)\depend.mk
+ $(SED) -e s`$(VTSF)`$$(VNBTSRC)`g <$(VNBTSRC)\depend.mk > $(VNBTSRC)\depend.tmp
+ $(SED) -e s`$(BASEDIRF)`$$(BASEDIR)`g <$(VNBTSRC)\depend.tmp > $(VNBTSRC)\depend.mk
+ $(SED) -e s`$(INCF)`$$(INC)`g <$(VNBTSRC)\depend.mk > $(VNBTSRC)\depend.tmp
+ $(SED) -e s`$(HF)`$$(H)`g <$(VNBTSRC)\depend.tmp > $(VNBTSRC)\depend.mk
+ $(SED) -e s`$(NDIS3F)`$$(NDIS3INC)`g <$(VNBTSRC)\depend.mk > $(VNBTSRC)\depend.tmp
+ $(SED) -e s`$(CHICAGOF)`$$(CHICAGO)`g <$(VNBTSRC)\depend.tmp > $(VNBTSRC)\depend.mk
+ $(SED) -e s`$(TCPF)`$$(TCP)`g <$(VNBTSRC)\depend.mk > $(VNBTSRC)\depend.tmp
+ copy $(VNBTSRC)\depend.tmp $(VNBTSRC)\depend.mk
+ -del $(VNBTSRC)\depend.tmp
+
+!include depend.mk
diff --git a/private/ntos/nbt/vxd/vxddebug.c b/private/ntos/nbt/vxd/vxddebug.c
new file mode 100644
index 000000000..663ccf780
--- /dev/null
+++ b/private/ntos/nbt/vxd/vxddebug.c
@@ -0,0 +1,659 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1993 **/
+/**********************************************************************/
+
+/*
+ debug.c
+
+ This module contains debug support routines.
+
+
+ FILE HISTORY:
+ KeithMo 20-Sep-1993 Created.
+
+*/
+
+#include <nbtprocs.h>
+#include <vxddebug.h>
+
+
+#ifdef DEBUG
+
+
+//
+// Private constants.
+//
+
+#define MAX_PRINTF_OUTPUT 1024 // characters
+#define MAX_SUBSTRING_LEN 256
+#define OUTPUT_LABEL "VNBT"
+
+#define IS_DIGIT(ch) (((ch) >= '0') && ((ch) <= '9'))
+
+
+//
+// Private types.
+//
+
+
+//
+// Private globals.
+//
+
+
+//
+// Private prototypes.
+//
+
+int VxdVsprintf( char * pszStr,
+ char * pszFmt,
+ char * ArgPtr );
+
+void VxdCopyToDBOut( void );
+
+//
+// Public functions.
+//
+
+/*******************************************************************
+
+ NAME: VxdAssert
+
+ SYNOPSIS: Called if an assertion fails. Displays the failed
+ assertion, file name, and line number. Gives the
+ user the opportunity to ignore the assertion or
+ break into the debugger.
+
+ ENTRY: pAssertion - The text of the failed expression.
+
+ pFileName - The containing source file.
+
+ nLineNumber - The guilty line number.
+
+ HISTORY:
+ KeithMo 20-Sep-1993 Created.
+
+********************************************************************/
+void VxdAssert( void * pAssertion,
+ void * pFileName,
+ unsigned long nLineNumber )
+{
+ VxdPrintf( "\n"
+ "*** Assertion failed: %s\n"
+ "*** Source file %s, line %lu\n\n",
+ pAssertion,
+ pFileName,
+ nLineNumber );
+
+ DEBUG_BREAK;
+
+} // VxdAssert
+
+/*******************************************************************
+
+ NAME: VxdPrintf
+
+ SYNOPSIS: Customized debug output routine.
+
+ ENTRY: Usual printf-style parameters.
+
+ HISTORY:
+ KeithMo 20-Sep-1993 Created.
+
+********************************************************************/
+char szOutput[MAX_PRINTF_OUTPUT];
+
+void VxdPrintf( char * pszFormat,
+ ... )
+{
+ va_list ArgList;
+ int cch;
+
+ cch = VxdSprintf( szOutput,
+ "%s: ",
+ OUTPUT_LABEL );
+
+ va_start( ArgList, pszFormat );
+ VxdVsprintf( szOutput + cch, pszFormat, ArgList );
+ va_end( ArgList );
+
+ VxdSprintf( szOutput, "%s\r\n", szOutput ) ;
+
+ VxdCopyToDBOut() ;
+
+ NbtDebugOut( DBOut+iCurPos ) ;
+
+} // VxdPrintf
+
+
+//
+// Private functions.
+//
+
+/*******************************************************************
+ NAME: VxdCopyToDBOut
+
+ SYNOPSIS: Copies everything from szOutput into DBOut
+ First checks to see if DBOut has enough room to hold what we
+ have temporarily put in szOutput. If not, resets the iCurPos
+ to point to beginning of DBOut.
+
+ RETURNS: Nothing
+
+ *******************************************************************/
+
+void VxdCopyToDBOut( void )
+{
+
+ int bytesTowrite;
+ int spaceAvailable;
+ int i;
+
+ spaceAvailable = sizeof(DBOut) - iCurPos;
+
+ bytesTowrite = strlen( szOutput ) + 1;
+
+ // if not enough room, start at the beginning
+ if ( spaceAvailable <= bytesTowrite )
+ {
+ for ( i=iCurPos; i<sizeof(DBOut); i++ )
+ DBOut[i] = '+'; // so that strings don't mix
+
+ iCurPos = 0;
+
+ if ( bytesTowrite > sizeof(szOutput) )
+ {
+ bytesTowrite = sizeof(szOutput);
+ szOutput[bytesTowrite-1] = '\0';
+ }
+ }
+
+ CTEMemCopy( DBOut+iCurPos, szOutput, bytesTowrite ) ;
+
+}
+
+/*******************************************************************
+
+ NAME: VxdVsprintf
+
+ SYNOPSIS: Half-baked vsprintf() clone for VxD environment.
+
+ ENTRY: pszStr - Will receive the formatted string.
+
+ pszFmt - The format, with field specifiers.
+
+ ArgPtr - Points to the actual printf() arguments.
+
+ RETURNS: int - Number of characters stored in *pszStr.
+
+ HISTORY:
+ KeithMo 20-Sep-1993 Created.
+
+********************************************************************/
+int VxdVsprintf( char * pszStr,
+ char * pszFmt,
+ char * ArgPtr )
+
+{
+ char ch;
+ char * pszStrStart;
+ int fZeroPad;
+ int cchWidth;
+ int ccMaxToCopy;
+
+ //
+ // Remember start of output, so we can calc length.
+ //
+
+ pszStrStart = pszStr;
+
+ while( ( ch = *pszFmt++ ) != '\0' )
+ {
+ //
+ // Scan for format specifiers.
+ //
+
+ if( ch != '%' )
+ {
+ *pszStr++ = ch;
+ continue;
+ }
+
+ //
+ // Got one.
+ //
+
+ ch = *pszFmt++;
+
+ //
+ // Initialize attributes for this item.
+ //
+
+ fZeroPad = 0;
+ cchWidth = 0;
+ ccMaxToCopy = MAX_SUBSTRING_LEN;
+
+ //
+ // Interpret the field specifiers.
+ //
+
+ if( ch == '-' )
+ {
+ //
+ // Left justification not supported.
+ //
+
+ ch = *pszFmt++;
+ }
+
+ if( ch == '0' )
+ {
+ //
+ // Zero padding.
+ //
+
+ fZeroPad = 1;
+ ch = *pszFmt++;
+ }
+
+ if( ch == '*' )
+ {
+ //
+ // Retrieve width from next argument.
+ //
+
+ cchWidth = va_arg( ArgPtr, int );
+ ch = *pszFmt++;
+ }
+ else
+ {
+ //
+ // Calculate width.
+ //
+
+ while( IS_DIGIT(ch) )
+ {
+ cchWidth = ( cchWidth * 10 ) + ( ch - '0' );
+ ch = *pszFmt++;
+ }
+ }
+
+ if( ch == '.' )
+ {
+ ch = *pszFmt++;
+
+ if( ch == '*' )
+ {
+ ccMaxToCopy = va_arg( ArgPtr, int );
+ ch = *pszFmt++;
+ }
+ else
+ {
+ ccMaxToCopy = 0;
+ while( IS_DIGIT(ch) )
+ {
+ ccMaxToCopy = ( ccMaxToCopy * 10 ) + ( ch - '0' );
+ ch = *pszFmt++;
+ }
+ }
+ }
+
+ //
+ // All numbers are longs.
+ //
+
+ if( ch == 'l' )
+ {
+ ch = *pszFmt++;
+ }
+
+ //
+ // Decipher the format specifier.
+ //
+
+ if( ( ch == 'd' ) || ( ch == 'u' ) || ( ch == 'x' ) || ( ch == 'X' ) )
+ {
+ unsigned long ul;
+ unsigned long radix;
+ char xbase;
+ char * pszTmp;
+ char * pszEnd;
+ int cchNum;
+ int fNegative;
+
+ //
+ // Numeric. Retrieve the value.
+ //
+
+ ul = va_arg( ArgPtr, unsigned long );
+
+ //
+ // If this is a negative number, remember and negate.
+ //
+
+ if( ( ch == 'd' ) && ( (long)ul < 0 ) )
+ {
+ fNegative = 1;
+ ul = (unsigned long)(-(long)ul);
+ }
+ else
+ {
+ fNegative = 0;
+ }
+
+ //
+ // Remember start of digits.
+ //
+
+ pszTmp = pszStr;
+ cchNum = 0;
+
+ //
+ // Special goodies for hex conversion.
+ //
+
+ radix = ( ( ch == 'x' ) || ( ch == 'X' ) ) ? 16 : 10;
+ xbase = ( ch == 'x' ) ? 'a' : 'A';
+
+ //
+ // Loop until we're out of digits.
+ //
+
+ do
+ {
+ unsigned int digit;
+
+ digit = (unsigned int)( ul % radix );
+ ul /= radix;
+
+ if( digit > 9 )
+ {
+ *pszTmp++ = (char)( digit - 10 + xbase );
+ }
+ else
+ {
+ *pszTmp++ = (char)( digit + '0' );
+ }
+
+ cchNum++;
+
+ } while( ul > 0 );
+
+ //
+ // Add the negative sign if necessary.
+ //
+
+ if( fNegative )
+ {
+ *pszTmp++ = '-';
+ cchNum++;
+ }
+
+ //
+ // Add any necessary padding.
+ //
+
+ while( cchNum < cchWidth )
+ {
+ *pszTmp++ = fZeroPad ? '0' : ' ';
+ cchNum++;
+ }
+
+ //
+ // Now reverse the digits.
+ //
+
+ pszEnd = pszTmp--;
+
+ do
+ {
+ char tmp;
+
+ tmp = *pszTmp;
+ *pszTmp = *pszStr;
+ *pszStr = tmp;
+
+ pszTmp--;
+ pszStr++;
+
+ } while( pszTmp > pszStr );
+
+ pszStr = pszEnd;
+ }
+ else
+ if( ch == 's' )
+ {
+ char * pszTmp;
+ int count;
+
+ //
+ // Copy the string.
+ //
+
+ pszTmp = va_arg( ArgPtr, char * );
+
+ count = 0;
+ while( *pszTmp )
+ {
+ *pszStr++ = *pszTmp++;
+ count++;
+ //
+ // if we get passed a weird pointer, don't go on writing! That
+ // overwrites other things (like tdidispatch table!) and very
+ // bad things happen....
+ //
+ if (count >= ccMaxToCopy)
+ break;
+ }
+ }
+ else
+ if( ch == 'c' )
+ {
+ //
+ // A single character.
+ //
+
+ *pszStr++ = (char)va_arg( ArgPtr, int );
+ }
+ else
+ {
+ //
+ // Unknown. Ideally we should copy the entire
+ // format specifier, including any width & precision
+ // values, but who really cares?
+ //
+
+ *pszStr++ = ch;
+ }
+ }
+
+ //
+ // Terminate it properly.
+ //
+
+ *pszStr = '\0';
+
+ //
+ // Return the length of the generated string.
+ //
+
+ return pszStr - pszStrStart;
+
+} // VxdVsprintf
+
+/*******************************************************************
+
+ NAME: VxdSprintf
+
+ SYNOPSIS: Half-baked sprintf() clone for VxD environment.
+
+ ENTRY: pszStr - Will receive the formatted string.
+
+ pszFmt - The format, with field specifiers.
+
+ ... - Usual printf()-like parameters.
+
+ RETURNS: int - Number of characters stored in *pszStr.
+
+ HISTORY:
+ KeithMo 20-Sep-1993 Created.
+
+********************************************************************/
+int VxdSprintf( char * pszStr,
+ char * pszFmt,
+ ... )
+{
+ int cch;
+ va_list ArgPtr;
+
+ va_start( ArgPtr, pszFmt );
+ cch = VxdVsprintf( pszStr, pszFmt, ArgPtr );
+ va_end( ArgPtr );
+
+ return( cch );
+
+} // VxdSprintf
+
+
+/*******************************************************************
+
+ NAME: DbgAllocMem
+
+ SYNOPSIS: Keep track of all allocated memory so we can catch
+ memory leak when we unload
+ This is only on debug builds. On non-debug builds
+ this function doesn't exist: calls directly go to
+ CTEAllocMem.
+
+ ENTRY: ReqSize - how much memory is needed
+
+ RETURNS: PVOID - pointer to the memory block that client will
+ use directly.
+
+ HISTORY:
+ Koti 11-Nov-1994 Created.
+
+********************************************************************/
+
+//
+// IMPORTANT: we are undef'ing CTEAllocMem because we need to make a
+// call to the actual CTE function CTEAllocMem. That's why
+// this function and this undef are at the end of the file.
+//
+#undef CTEAllocMem
+PVOID DbgAllocMem( DWORD ReqSize )
+{
+
+ DWORD ActualSize;
+ PVOID pBuffer;
+ DbgMemBlkHdr *pMemHdr;
+ PVOID pRetAddr;
+
+
+ ActualSize = ReqSize + sizeof(DbgMemBlkHdr);
+ pBuffer = CTEAllocMem( ActualSize );
+ if ( !pBuffer )
+ {
+ return( NULL );
+ }
+
+ pMemHdr = (DbgMemBlkHdr *)pBuffer;
+
+ pMemHdr->Verify = DBG_MEMALLOC_VERIFY;
+ pMemHdr->ReqSize = ReqSize;
+ pRetAddr = &pMemHdr->Owner[0];
+
+//
+// now memory is allocated from NCBHandler, too where stack trace isn't more
+// than 2 deep! unifdef when memory leaks becomes an issue...
+//
+#if 0
+ _asm
+ {
+ push ebx
+ push ecx
+ push edx
+ mov ebx, pRetAddr
+ mov eax, ebp
+ mov ecx, 4
+ again:
+ mov edx, dword ptr [eax+4] ; return address
+ mov dword ptr [ebx], edx
+ mov eax, dword ptr [eax] ; previous frame pointer
+ add ebx, 4
+ dec ecx
+ cmp ecx, 0
+ je done
+ jmp again
+ done:
+ pop edx
+ pop ecx
+ pop ebx
+ }
+#endif
+
+ //
+ // BUGBUG: if ever ported to NT (or if chicago needs MP support),
+ // put spinlocks. (we will need a spinlock field in DbgMemBlkHdr struct).
+ //
+ InsertTailList(&DbgMemList, &pMemHdr->Linkage);
+
+ return( (PCHAR)pBuffer + sizeof(DbgMemBlkHdr) );
+}
+
+/*******************************************************************
+
+ NAME: DbgFreeMem
+
+ SYNOPSIS: This routine removes the memory block from our list and
+ frees the memory by calling the CTE function CTEFreeMem
+
+ ENTRY: pBufferToFree - memory to free (caller's buffer)
+
+ RETURNS: nothing
+
+ HISTORY:
+ Koti 11-Nov-1994 Created.
+
+********************************************************************/
+
+//
+// IMPORTANT: we are undef'ing CTEFreeMem because we need to make a
+// call to the actual CTE function CTEFreeMem. That's why
+// this function and this undef are at the end of the file.
+//
+#undef CTEMemFree
+#undef CTEFreeMem
+
+VOID DbgFreeMem( PVOID pBufferToFree )
+{
+
+ DbgMemBlkHdr *pMemHdr;
+
+
+ if ( !pBufferToFree )
+ {
+ return;
+ }
+
+ pMemHdr = (DbgMemBlkHdr *)((PCHAR)pBufferToFree - sizeof(DbgMemBlkHdr));
+
+ ASSERT( pMemHdr->Verify == DBG_MEMALLOC_VERIFY );
+
+ //
+ // change our signature: if we are freeing some memory twice, we'll know!
+ //
+ pMemHdr->Verify -= 1;
+
+ //
+ // BUGBUG: if ever ported to NT (or if chicago needs MP support),
+ // put spinlocks. (we will need a spinlock field in DbgMemBlkHdr struct).
+ //
+ RemoveEntryList(&pMemHdr->Linkage);
+
+ CTEFreeMem( (PVOID)pMemHdr );
+}
+
+#endif // DEBUG
+
diff --git a/private/ntos/nbt/vxd/vxdfile.asm b/private/ntos/nbt/vxd/vxdfile.asm
new file mode 100644
index 000000000..05c7e855d
--- /dev/null
+++ b/private/ntos/nbt/vxd/vxdfile.asm
@@ -0,0 +1,314 @@
+;/**********************************************************************/
+;/** Microsoft Windows/NT **/
+;/** Copyright(c) Microsoft Corp., 1993 **/
+;/**********************************************************************/
+
+;/*
+; vxdFile.asm
+;
+; Contains simple VXD File I/O routines for lmhosts support
+;
+; FILE HISTORY:
+; Johnl 06-Oct-1993 Created
+;
+;*/
+
+ .386p
+ include vmm.inc
+ include v86mmgr.inc
+ include dosmgr.inc
+ include opttest.inc
+ include netvxd.inc
+ include debug.inc
+
+;
+; Must match manifest in vxd\fileio.c
+;
+LMHOSTS_READ_BUFF_SIZE equ 256
+
+EXTRN _pMappedFilePath:DWORD
+EXTRN _pMappedFileBuff:DWORD
+EXTRN _pFileBuff:DWORD
+EXTRN _pFilePath:DWORD
+EXTRN _fInInit:DWORD
+
+EXTRN _GetInDosFlag:NEAR
+
+;****************************************************************************
+;** CheckInDos Macro
+;
+; Breaks if the Indos flag is set
+;
+; Uses EAX
+;
+CheckInDos MACRO
+IFDEF DEBUG
+ push eax
+ cmp _fInInit, 0 ; Can't call while initializing
+ jnz @f
+ call _GetInDosFlag
+ cmp ax, 0
+ je @f
+ Debug_Out "In dos flag set and about to make dos call!"
+@@:
+ pop eax
+ENDIF
+ENDM
+
+;****************************************************************************
+;** PushState Macro
+;
+; Saves the client state and begins nested exec block. ebx will contain
+; the current VM's client handle
+;
+; Uses ECX!!
+; EBX will be set to the client area
+;
+PushState MACRO
+
+ CheckInDos
+
+ push ebx
+ VMMcall Get_Cur_VM_Handle ; Puts current handle into EBX
+ mov ebx, [ebx.CB_Client_Pointer]
+
+ mov ecx, 0
+ VMMCall Begin_Critical_Section
+
+ Push_Client_State ; This pushes lots of crap
+ VMMcall Begin_Nest_V86_Exec
+ENDM
+
+;****************************************************************************
+;** PopState Macro
+;
+; Restores client state and ends the nested exec block
+;
+;
+PopState MACRO
+
+ VMMcall End_Nest_Exec
+ Pop_Client_State
+
+ VMMCall End_Critical_Section
+
+ pop ebx
+
+ENDM
+
+
+VxD_ICODE_SEG
+
+;****************************************************************************
+;** _VxdInitLmHostsSupport
+;
+; Allocates and maps memory for lmhosts support
+;
+; This is an Init time only routine
+;
+; Entry: [ESP+4] - Pointer to full path of file,
+; [ESP+8] - strlen of path
+;
+; Exit: TRUE if successful, FALSE otherwise
+;
+BeginProc _VxdInitLmHostsSupport
+ push esi
+ push edi
+
+ mov ecx, [esp+16]
+ add ecx, LMHOSTS_READ_BUFF_SIZE
+
+ push ecx ; save ecx for the map call
+ VMMCall _Allocate_Global_V86_Data_Area, <ecx, GVDAZeroInit>
+ pop ecx
+ or eax,eax ; zero if error
+ jz ILMH_50
+
+ push eax
+ mov _pFileBuff, eax ; Save the linear address so we can access
+ add eax, LMHOSTS_READ_BUFF_SIZE ; from the vxd
+ mov _pFilePath, eax
+ pop eax
+
+ shl eax, 12 ; Convert linear to V86 address
+ shr ax, 12
+
+ mov _pMappedFileBuff, eax
+ add eax, LMHOSTS_READ_BUFF_SIZE
+ mov _pMappedFilePath, eax
+
+ jmp ILMH_70
+
+ILMH_40:
+ ; Free allocated V86 global memory (how?)
+
+
+ILMH_50:
+ ; error occurred, eax already contains zero
+
+
+ILMH_70:
+ pop edi
+ pop esi
+ ret
+
+EndProc _VxdInitLmHostsSupport
+
+
+;****************************************************************************
+;** _VxdWindowsPath
+;
+; Gets a pointer to (null-terminated) path to the windows directory
+;
+; This is an Init time only routine
+;
+; Entry: nothing
+;
+; Exit: pointer to path to windows directory
+;
+BeginProc _VxdWindowsPath
+ PushState ; Pushes lots of crap
+
+ VmmCall Get_Config_Directory
+
+ mov eax, edx ; path is returned in edx
+
+ PopState ; now pop all that crap
+
+ ret
+
+EndProc _VxdWindowsPath
+
+VxD_ICODE_ENDS
+
+VxD_CODE_SEG
+
+;****************************************************************************
+;** _VxdFileOpen
+;
+; Opens a file
+;
+; Entry: [ESP+4] - Pointer to full path of file, path must be mapped
+; to v86 memory before calling this
+;
+; Exit: EAX will contain a handle to the openned file
+;
+BeginProc _VxdFileOpen
+
+ push edi
+ push esi
+
+ mov dx, word ptr [esp+12] ; Just the offset
+ mov di, word ptr [esp+14] ; Just the segment
+
+ PushState ; This pushes lots of crap
+
+ mov [ebx.Client_ax], 3d00h ; Open file, read only, share
+ mov [ebx.Client_dx], dx
+ mov [ebx.Client_ds], di
+
+ mov eax, 21h
+ VmmCall Exec_Int
+ test [ebx.Client_Flags], CF_Mask ; Carry set if error
+ jz VFO_6 ; Carry set if error
+
+ mov eax, 0 ; Failed to open the file
+ jmp VFO_10
+
+VFO_6:
+ movzx eax, [ebx.Client_ax] ; Handle of file
+
+VFO_10:
+ PopState
+
+ pop esi
+ pop edi
+ ret
+EndProc _VxdFileOpen
+
+
+;****************************************************************************
+;** _VxdFileRead
+;
+; Reads x bytes from a previously openned file
+;
+; Entry: [ESP+4] - Handle from _VxdFileOpen
+; [ESP+8] - Count of bytes to read
+; [ESP+12]- Mapped memory of destination buffer
+;
+; Exit: EAX will contain the number of bytes read, 0 if EOF or
+; an error occurred.
+;
+BeginProc _VxdFileRead
+
+ push edi
+ push esi
+
+ mov ax, [esp+12] ; File Handle
+ mov si, [esp+16] ; Bytes to read
+ mov dx, [esp+20] ; Just the offset
+ mov di, [esp+22] ; Just the segment
+
+ PushState ; Pushes lots of crap (uses cx)
+
+ mov [ebx.Client_ax], 3f00h ; File Read
+ mov [ebx.Client_bx], ax ; File Handle
+ mov [ebx.Client_cx], si ; Bytes to read
+ mov [ebx.Client_dx], dx ; Mapped destination buffer
+ mov [ebx.Client_ds], di
+
+ mov eax, 21h
+ VmmCall Exec_Int
+ test [ebx.Client_Flags], CF_Mask ; Carry set if error
+ jz VFR_6 ; Carry set if error
+
+ mov eax, 0 ; Failed to open the file
+ jmp VFR_7
+
+VFR_6:
+ movzx eax, [ebx.Client_ax] ; Bytes read
+
+VFR_7:
+
+VFR_10:
+ PopState
+
+ pop esi
+ pop edi
+ ret
+EndProc _VxdFileRead
+
+
+;****************************************************************************
+;** _VxdFileClose
+;
+; Closes a file openned with VxdOpenFile
+;
+; Entry: [ESP+4] - Handle from _VxdFileOpen
+;
+BeginProc _VxdFileClose
+
+ mov ax, [esp+4] ; File Handle
+
+ PushState ; Pushes lots of crap
+
+ mov [ebx.Client_ax], 3e00h ; File Close
+ mov [ebx.Client_bx], ax ; File Handle
+
+ mov eax, 21h
+ VmmCall Exec_Int
+ test [ebx.Client_Flags], CF_Mask ; Carry set if error
+ jz VFCL_10 ; Carry set if error
+
+ Debug_Out "VxdFileClose - Close failed"
+ mov eax, 0 ; Failed to close the file
+
+VFCL_10:
+ PopState
+
+ ret
+EndProc _VxdFileClose
+
+
+VxD_CODE_ENDS
+END
diff --git a/private/ntos/nbt/vxd/vxdisol.c b/private/ntos/nbt/vxd/vxdisol.c
new file mode 100644
index 000000000..7c5e6dfe1
--- /dev/null
+++ b/private/ntos/nbt/vxd/vxdisol.c
@@ -0,0 +1,4042 @@
+/**********************************************************************/
+/** Microsoft Windows/NT **/
+/** Copyright(c) Microsoft Corp., 1993 **/
+/**********************************************************************/
+
+/*
+ VxdIsol.c
+
+ This file roughly corresponds to ntisol.c and contains VxD specific
+ portions of the NBT driver
+
+ FILE HISTORY:
+ Johnl 15-Apr-1993 Created
+
+*/
+
+
+#include <nbtprocs.h>
+#include <nbtioctl.h>
+
+//
+// Used by VxdFindClientElement
+//
+enum CLIENT_TYPE
+{
+ CLIENT_BC,
+ CLIENT_LOCAL
+} ;
+
+//
+// Counts the number of items in the list Head
+//
+// Assumes pEntry is defined in the procedure
+//
+#define COUNT_ELEMENTS( Head, Count ) \
+ for ( pEntry = (Head).Flink ; \
+ pEntry != &(Head); \
+ pEntry = pEntry->Flink ) \
+ { \
+ (Count)++ ; \
+ }
+
+extern BOOLEAN CachePrimed;
+extern BOOL fInInit;
+
+//
+// this is used for AdapterStatus and FindName calls because we need to retain
+// the info, so can't have it as a local var (both these calls are synchronous
+// so need not worry about stomping on this memory)
+//
+TA_NETBIOS_ADDRESS tanb_global ;
+
+
+NCBERR VxdNameToClient( tDEVICECONTEXT * pDeviceContext,
+ CHAR * pName,
+ UCHAR * pNameNum,
+ tCLIENTELE * * ppClientEle ) ;
+
+//-------------------------------------------------------------------------
+//
+// Allocates and frees the SESS_SETUP_CONTEXT contents (not the context
+// itself).
+//
+TDI_STATUS AllocSessSetupContext( PSESS_SETUP_CONTEXT pSessSetupContext,
+ BOOL fListenOnStar ) ;
+void FreeSessSetupContext( PSESS_SETUP_CONTEXT pSessSetupContext ) ;
+
+NCBERR VxdInitSessionSetup( tDEVICECONTEXT * pDeviceContext,
+ TDI_REQUEST * pRequest,
+ PSESS_SETUP_CONTEXT * ppSessSetupContext,
+ NCB * pNCB ) ;
+
+BOOL VxdCopySessionStatus( tDEVICECONTEXT * pDeviceContext,
+ tCLIENTELE * pClientEle,
+ PSESSION_HEADER pSessionHeader,
+ PSESSION_BUFFER * ppSessionBuff,
+ ULONG * pRemainingSize ) ;
+
+//-------------------------------------------------------------------------
+//
+// NCB Reset context structures
+//
+//
+
+typedef struct
+{
+ //
+ // Number of active sessions we are waiting on to close
+ //
+ int cActiveSessions ;
+
+ //
+ // Number of active names we have to wait to finish deregistering
+ //
+ int cActiveNames ;
+
+ //
+ // NCB Error if reset failed (failed to resize session table for example)
+ //
+ UCHAR errncb ;
+} RESET_CONTEXT, *PRESET_CONTEXT ;
+
+NCBERR VxdResetContinue( tDEVICECONTEXT * pDeviceContext, NCB * pNCB ) ;
+
+#define DISCONNECT_TIMEOUT 15000
+
+//-------------------------------------------------------------------------
+//
+// Last valid NCB name and logical session number
+//
+#define MAX_NCB_NUMS 254
+#define ANY_NAME 255
+
+NTSTATUS
+PostInit_Proc();
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGE, PostInit_Proc)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+/*******************************************************************
+
+ NAME: VxdDgramSend
+
+ SYNOPSIS: Vxd specific Send Datagram code
+
+ ENTRY: pDeviceContext - Device to send the datagram on
+ pNCB - NCB that contains the datagram data/dest
+
+ RETURNS: NT_SUCCESS if successful, error otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 19-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdDgramSend( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status;
+ LONG lSentLength;
+ TDI_REQUEST Request;
+ tDGRAMHDR *pDgramHdr;
+ tCLIENTELE *pClientEle;
+ char *pName ;
+ NCBERR errNCB ;
+ TDI_CONNECTION_INFORMATION SendInfo ;
+ TA_NETBIOS_ADDRESS tanb ;
+
+
+ errNCB = VxdFindClientElement( pDeviceContext,
+ pNCB->ncb_num,
+ &pClientEle,
+ CLIENT_LOCAL ) ;
+ if ( errNCB )
+ {
+ DbgPrint("VxdDgramSend: VxdFindClientElement Failed\r\n") ;
+ return errNCB ;
+ }
+
+ ASSERT( pClientEle->Verify == NBT_VERIFY_CLIENT ) ;
+
+ if ( pClientEle->fDeregistered )
+ return NRC_NOWILD ;
+
+ //
+ // If broadcast, then use "*" for destination name
+ //
+ if ( (pNCB->ncb_command & ~ASYNCH) == NCBDGSENDBC )
+ {
+ //
+ // Name must stay valid after call
+ //
+ static char BcastName[NCBNAMSZ] = "* " ;
+ pName = BcastName ;
+ }
+ else
+ {
+ pName = pNCB->ncb_callname ;
+ }
+
+ //
+ // Initialize the transport address
+ //
+ // It's Ok to pass automatic variables to NbtSendDatagram,
+ // the necessary data is copied out before returning
+ //
+ InitNBTDIConnectInfo( &SendInfo, &tanb, pName ) ;
+ Request.Handle.AddressHandle = pClientEle;
+
+ status = NbtSendDatagram(
+ &Request,
+ &SendInfo,
+ pNCB->ncb_length,
+ &lSentLength,
+ pNCB->ncb_buffer, // user data
+ pDeviceContext,
+ (PIRP) pNCB );
+
+ errNCB = MapTDIStatus2NCBErr( status ) ;
+
+ if ( errNCB != NRC_GOODRET && errNCB != NRC_PENDING)
+ {
+ DbgPrint("VxdDgramSend - returning ncb status 0x" ) ;
+ DbgPrintNum( (ULONG) errNCB ) ;
+ DbgPrint("\r\n") ;
+ }
+ else
+ {
+ //
+ // Since NbtSendDatagram always buffers datagram sends, we need to
+ // complete the NCB here since NbtSendDatagram will not complete
+ // the data gram
+ //
+ CTEIoComplete(pNCB,status,pNCB->ncb_length);
+ }
+
+ return errNCB ;
+}
+
+/*******************************************************************
+
+ NAME: VxdDgramReceive
+
+ SYNOPSIS: Vxd specific Datagram Receive code
+
+ ENTRY: pDeviceContext - Device to send the datagram on
+ pNCB - NCB that contains the datagram data/dest
+
+ RETURNS: NT_SUCCESS if successful, error otherwise
+
+ NOTES: For a receive datagram, the name number is who we want to
+ receive to, and the call name will be set to who we
+ received from. The name number may be 0xff to indicate
+ receive to any name from anyone.
+
+ HISTORY:
+ Johnl 19-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdDgramReceive( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ TDI_REQUEST Request;
+ ULONG ReceivedLength;
+ tCLIENTELE * pClientEle ;
+ NCBERR errNCB ;
+ TDI_CONNECTION_INFORMATION RcvInfo ;
+ TDI_CONNECTION_INFORMATION SendInfo ;
+ NTSTATUS status ;
+
+ if ( pNCB->ncb_num != ANY_NAME )
+ {
+ //
+ // For the RcvBC case, this just confirms the ncb_num is valid, the
+ // pClientEle is replaced with the broadcast client element (mif
+ // tests invalid ncb_nums with broadcasts).
+ //
+ if ( errNCB = VxdFindClientElement( pDeviceContext,
+ pNCB->ncb_num,
+ &pClientEle,
+ CLIENT_LOCAL ) )
+ {
+ return errNCB ;
+ }
+
+ if ( pClientEle->fDeregistered )
+ return NRC_NOWILD ;
+
+ if ( (pNCB->ncb_command & ~ASYNCH) == NCBDGRECVBC )
+ {
+ if ( errNCB = VxdFindClientElement( pDeviceContext,
+ pNCB->ncb_num,
+ &pClientEle,
+ CLIENT_BC ) )
+ if ( errNCB )
+ return NRC_NAMERR ;
+ }
+
+ Request.Handle.AddressHandle = pClientEle ;
+
+ status = NbtReceiveDatagram(
+ &Request,
+ NULL, //pTdiRequest->ReceiveDatagramInformation,
+ NULL, //pTdiRequest->ReturnDatagramInformation,
+ pNCB->ncb_length,
+ &ReceivedLength,
+ pNCB->ncb_buffer, // user data
+ pDeviceContext,
+ pNCB );
+ if ( status == STATUS_PENDING )
+ return NRC_PENDING ;
+ }
+ else
+ {
+ tRCVELE * pRcvEle = (tRCVELE *)CTEAllocMem(sizeof(tRCVELE));
+ if (!pRcvEle)
+ return NRC_NORES ;
+
+ pRcvEle->pIrp = pNCB ;
+ pRcvEle->ReceiveInfo = NULL ;
+ pRcvEle->ReturnedInfo = NULL;
+ pRcvEle->RcvLength = pNCB->ncb_length ;
+ pRcvEle->pRcvBuffer = pNCB->ncb_buffer ;
+
+ InsertTailList( &pDeviceContext->RcvDGAnyFromAnyHead,
+ &pRcvEle->Linkage );
+
+ return NRC_PENDING ;
+ }
+
+ //
+ // Status should always be pending or error
+ //
+ ASSERT( status != TDI_SUCCESS ) ;
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCall
+
+ SYNOPSIS: Attempts to setup a session with the corresponding listen
+
+ ENTRY: pDeviceContext - Adapter to call on
+ pNCB - NCB that contains the call command
+
+ RETURNS:
+
+ NOTES: Before we can do the listen we must first open the
+ connection and associate the address.
+
+ The reserve field of the NCB is used as a SESS_SETUP_CONTEXT
+ structure
+
+ HISTORY:
+ Johnl 14-May-1993 Created
+
+********************************************************************/
+
+NCBERR VxdCall( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status;
+ NCBERR errNCB ;
+ TDI_REQUEST Request;
+ PSESS_SETUP_CONTEXT pSessSetupContext = NULL ;
+
+ if ( ( pNCB->ncb_name[0] == '*' )
+ || ( pNCB->ncb_callname[0] == '*' ) )
+ {
+ return NRC_NOWILD ;
+ }
+
+ if ( errNCB = VxdInitSessionSetup( pDeviceContext,
+ &Request,
+ &pSessSetupContext,
+ pNCB ))
+ {
+ return errNCB ;
+ }
+
+ status = NbtConnect( &Request,
+ 0, // Use system timeout
+ pSessSetupContext->pRequestConnect,
+ pSessSetupContext->pReturnConnect,
+ pNCB
+ );
+
+ if ( !NT_SUCCESS(status) )
+ {
+ VxdTearDownSession( pDeviceContext,
+ (tCONNECTELE*)Request.Handle.ConnectionContext,
+ pSessSetupContext,
+ NULL ) ;
+ }
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdSend
+
+ SYNOPSIS: Sends a netbios request
+
+ ENTRY: pDeviceContext - Adapter to call on
+ pNCB - NCB that contains the send command
+
+ EXIT:
+
+ RETURNS:
+
+ NOTES: pNCB->ncb_lsn - Session number to Send on
+
+ pNCB->ncb_reserved will contain a pointer to a tSESSIONHDR
+ for this NCB (freed in VxdIoComplete).
+
+ No-ack sends are treated like normal sends.
+
+ HISTORY:
+ Johnl 8-Jun-1993 Created
+
+********************************************************************/
+
+NCBERR VxdSend( tDEVICECONTEXT *pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status ;
+ NCBERR errNCB ;
+ tCONNECTELE * pConnEle;
+ CTELockHandle OldIrq;
+ tLOWERCONNECTION * pLowerConn;
+ tSESSIONHDR * pHdr=NULL;
+ tBUFFERCHAINSEND SendBuff ;
+ TDI_REQUEST Request ;
+ ULONG SentSize ;
+ ULONG SendFlags = 0 ;
+ PSEND_CONTEXT pSendCont = (PSEND_CONTEXT) pNCB->ncb_reserve ;
+
+ ASSERT( sizeof(SEND_CONTEXT) <=
+ sizeof(pNCB->ncb_reserve)+sizeof(pNCB->ncb_event)) ;
+
+ if ( errNCB = VxdFindConnectElement( pDeviceContext,
+ pNCB,
+ &pConnEle ))
+ {
+ return errNCB ;
+ }
+
+ ASSERT( pConnEle->Verify == NBT_VERIFY_CONNECTION ) ;
+
+ pLowerConn = (tLOWERCONNECTION *)pConnEle->pLowerConnId ;
+
+ // check the state of the connection
+ if (pConnEle->state == NBT_SESSION_UP)
+ {
+ if ( GetSessionHdr( &pHdr ))
+ {
+ //
+ // If this is part of a chain send, set up the 2nd buffer
+ //
+ if ( ((pNCB->ncb_command & ~ASYNCH) == NCBCHAINSEND) ||
+ ((pNCB->ncb_command & ~ASYNCH) == NCBCHAINSENDNA) )
+ {
+ SendBuff.Length2 = *((WORD*)pNCB->ncb_callname) ;
+ SendBuff.pBuffer2 = *((PUCHAR*)(pNCB->ncb_callname+2)) ;
+ SendFlags |= CHAIN_SEND_FLAG ;
+ DbgPrint("VxdSend - Doing chain send\r\n") ;
+ }
+ else
+ {
+ SendBuff.Length2 = 0 ;
+ }
+
+ pHdr->Type = NBT_SESSION_MESSAGE ;
+ pHdr->Flags = NBT_SESSION_FLAGS ;
+ pHdr->UlongLength = htonl(pNCB->ncb_length + SendBuff.Length2) ;
+
+ pSendCont->pHdr = pHdr ;
+
+ //
+ // Only sends that can time out are put on the timeout list
+ //
+ if ( (pSendCont->STO = pConnEle->STO) != NCB_INFINITE_TIME_OUT )
+ {
+ InsertTailList( &NbtConfig.SendTimeoutHead, &pSendCont->ListEntry ) ;
+ }
+
+ SendBuff.tBuff.pDgramHdr = pHdr ;
+ SendBuff.tBuff.HdrLength = sizeof( *pHdr ) ;
+ SendBuff.tBuff.pBuffer = pNCB->ncb_buffer ;
+ SendBuff.tBuff.Length = pNCB->ncb_length ;
+
+#ifdef DEBUG
+ if ( !pNCB->ncb_length ) // Make sure 0 length buffers do
+ SendBuff.tBuff.pBuffer = NULL ; // the right thing
+#endif
+
+ Request.RequestNotifyObject = VxdIoComplete ;
+ Request.RequestContext = pNCB ;
+ Request.Handle.ConnectionContext = pConnEle->pLowerConnId->pFileObject ;
+
+ status = TdiSend( &Request,
+ 0,
+ (USHORT) SendBuff.tBuff.HdrLength +
+ SendBuff.tBuff.Length + SendBuff.Length2,
+ &SentSize,
+ (tBUFFER*) &SendBuff,
+ SendFlags ) ;
+ ASSERT( !NT_SUCCESS( status ) ||
+ (SentSize == (SendBuff.tBuff.HdrLength +
+ SendBuff.tBuff.Length + SendBuff.Length2)) ) ;
+
+ pLowerConn->BytesSent += SentSize;
+
+ return NRC_PENDING ;
+
+ //
+ // if TdiSend fails, it will call the completion routine (directly
+ // or eventually, Vxdiocomplete) which will remove this from the list
+ // so, don't remove it here also or we overwrite redir's code segment!!
+ //
+ // //
+ // // Remove from the timeout list if an error occurred
+ // //
+ // if ( !NT_SUCCESS( status ) &&
+ // pConnEle->STO != NCB_INFINITE_TIME_OUT )
+ // {
+ // RemoveEntryList( &pSendCont->ListEntry ) ;
+ // }
+ }
+ else
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES ;
+ goto ErrorExit ;
+ }
+ }
+ else
+ {
+ status = TDI_INVALID_CONNECTION ;
+ }
+
+ if ( !NT_SUCCESS( status ) )
+ goto ErrorExit ;
+
+
+ return MapTDIStatus2NCBErr( status ) ;
+
+ErrorExit:
+ if ( pHdr )
+ FreeSessionHdr( pHdr ) ;
+
+ DbgPrint("VxdSend returning NCB error: 0x") ;
+ DbgPrintNum( MapTDIStatus2NCBErr( status ) ) ; DbgPrint("\r\n") ;
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdReceiveAny
+
+ SYNOPSIS: Handles a request to accept data from any open session
+
+ ENTRY: pDeviceContext - Adapter to call on
+ pNCB - NCB that contains the receive command
+
+ EXIT:
+
+ RETURNS:
+
+ NOTES: pNCB->ncb_lsn - Session set to who to receive from if
+ an indication is found
+
+ The most common case (for WFW rdr) is to Receive on
+ a particular name number w/o any waiting connections
+
+ HISTORY:
+ Johnl 8-Jun-1993 Created
+
+********************************************************************/
+
+NCBERR VxdReceiveAny( tDEVICECONTEXT *pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status;
+ NCBERR errNCB ;
+ tLOWERCONNECTION * pLowerConn;
+ tCLIENTELE * pClientEle = NULL ;
+ PLIST_ENTRY pEntry, pHead ;
+
+#ifdef DEBUG
+ DbgPrint("VxdReceiveAny posted: Ncb length, Rcv Buff Address: 0x") ;
+ DbgPrintNum( pNCB->ncb_length ) ; DbgPrint(", 0x") ;
+ DbgPrintNum( (ULONG) pNCB->ncb_buffer ) ; DbgPrint("\r\n") ;
+#endif
+
+ //
+ // If they've given us a name number to receive on, find it
+ //
+ if ( pNCB->ncb_num != ANY_NAME )
+ {
+ if ( errNCB = VxdFindClientElement( pDeviceContext,
+ pNCB->ncb_num,
+ &pClientEle,
+ CLIENT_LOCAL ) )
+ {
+ DbgPrint("VxdReceiveAny - Couldn't find name number\r\n") ;
+ return errNCB ;
+ }
+
+ if ( !pClientEle->fDeregistered )
+ {
+ if ( IsListEmpty( &pDeviceContext->PartialRcvHead ) )
+ {
+ goto QueueRcv ;
+ }
+ }
+ else
+ {
+ return NRC_NOWILD ;
+ }
+ }
+ else
+ {
+ if ( IsListEmpty( &pDeviceContext->PartialRcvHead ) )
+ {
+ goto QueueRcv ;
+ }
+ }
+
+ //
+ // Scan for all active sessions looking for one that has indicated
+ // data that will satisfy this ReceiveAny
+ //
+ pHead = &pDeviceContext->PartialRcvHead ;
+ pEntry = pHead->Flink ;
+ ASSERT( pEntry );
+ while ( pEntry != pHead )
+ {
+ DbgPrint("VxdReceiveAny: scanning lower connections for partial receive\r\n") ;
+ pLowerConn = CONTAINING_RECORD( pEntry, tLOWERCONNECTION, PartialRcvList ) ;
+
+ ASSERT( pLowerConn->State < NBT_DISCONNECTING );
+ //
+ // If Receive any from any, then the first one we find
+ // will work, otherwise compare the names
+ //
+
+ if ( pNCB->ncb_num == ANY_NAME )
+ break ;
+
+ else
+ {
+ if ( CTEMemCmp( pClientEle->pAddress->pNameAddr->Name,
+ pLowerConn->pUpperConnection->pClientEle->
+ pAddress->pNameAddr->Name,
+ NETBIOS_NAME_SIZE ) == NETBIOS_NAME_SIZE )
+ {
+ break ;
+ }
+ }
+
+ pEntry = pEntry->Flink ;
+ }
+
+ if ( pEntry != pHead )
+ {
+ DbgPrint("VxdReceiveAny: Found partial receive, calling VxdReceive\r\n") ;
+
+ ASSERT (pLowerConn->fOnPartialRcvList == TRUE);
+ RemoveEntryList( &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+
+ //
+ // Now find the session number this receive is taking place on
+ //
+ if ( errNCB = VxdFindLSN( pDeviceContext,
+ pLowerConn->pUpperConnection,
+ &pNCB->ncb_lsn ))
+ {
+ return errNCB ;
+ }
+
+ return VxdReceive( pDeviceContext, pNCB, FALSE ) ;
+ }
+ else
+ {
+ //
+ // Nothing active so queue it
+ //
+ PRCV_CONTEXT prcvCont ;
+
+QueueRcv:
+ if ( !GetRcvContext( &prcvCont ))
+ return NRC_NORESOURCES ;
+
+ InitRcvContext( prcvCont, NULL, pNCB ) ;
+ InitNDISBuff( &prcvCont->ndisBuff,
+ pNCB->ncb_buffer,
+ pNCB->ncb_length,
+ NULL ) ;
+ prcvCont->usFlags = TDI_RECEIVE_NORMAL;
+ *((PRCV_CONTEXT*)&pNCB->ncb_reserve) = prcvCont ;
+
+ if ( pNCB->ncb_num != ANY_NAME )
+ {
+ ASSERT( pClientEle != NULL ) ;
+ InsertTailList( &pClientEle->RcvAnyHead,
+ &prcvCont->ListEntry ) ;
+
+ return NRC_PENDING ;
+ }
+ else
+ {
+ InsertTailList( &pDeviceContext->RcvAnyFromAnyHead,
+ &prcvCont->ListEntry ) ;
+ }
+ }
+
+ return NRC_PENDING ;
+}
+
+/*******************************************************************
+
+ NAME: VxdReceive
+
+ SYNOPSIS: Worker for VxdReceive and VxdReceiveAny
+
+ ENTRY: pDeviceContext - Adapter to call on
+ pNCB - NCB that contains the receive command
+ fReceive - TRUE if we got here via a Receive ncb
+ - FALSE if we got here via a ReceiveAny ncb
+ EXIT:
+
+ RETURNS:
+
+ NOTES: pNCB->ncb_reserved will contain a pointer to a RCV_CONTEXT
+ for this NCB.
+
+ VxdReceiveAny calls this on an element where state==NBT_SESSION_UP
+ and StateRcv == PARTIAL_RCV, thus the receive context should
+ never be added to pConnele->RcvHead.
+
+ HISTORY:
+ Johnl 8-Jun-1993 Created
+
+********************************************************************/
+
+NCBERR VxdReceive( tDEVICECONTEXT * pDeviceContext, NCB * pNCB, BOOL fReceive )
+{
+ NTSTATUS status;
+ NCBERR errNCB ;
+ tCONNECTELE * pConnEle;
+ CTELockHandle OldIrq;
+ tLOWERCONNECTION * pLowerConn;
+ PRCV_CONTEXT prcvCont ;
+
+ if ( errNCB = VxdFindConnectElement( pDeviceContext,
+ pNCB,
+ &pConnEle ))
+ {
+ return errNCB ;
+ }
+
+ ASSERT( pConnEle->Verify == NBT_VERIFY_CONNECTION ) ;
+
+ pLowerConn = pConnEle->pLowerConnId;
+
+ DbgPrint("VxdReceive posted: Ncb length, Rcv buff Address: 0x") ;
+ DbgPrintNum( pNCB->ncb_length ) ; DbgPrint(", 0x") ;
+ DbgPrintNum( (ULONG) pNCB->ncb_buffer ) ; DbgPrint("\r\n") ;
+
+ //
+ // Setup the receive context tracker
+ //
+ if ( GetRcvContext( &prcvCont ))
+ {
+ InitRcvContext( prcvCont, pLowerConn, pNCB ) ;
+ InitNDISBuff( &prcvCont->ndisBuff,
+ pNCB->ncb_buffer,
+ pNCB->ncb_length,
+ NULL ) ;
+ prcvCont->RTO = pConnEle->RTO ;
+ prcvCont->usFlags = TDI_RECEIVE_NORMAL;
+
+ *((PRCV_CONTEXT*)&pNCB->ncb_reserve) = prcvCont ;
+
+ //
+ // If data is not available, queue the request, otherwise get the
+ // data
+ //
+ if ( pLowerConn->StateRcv != PARTIAL_RCV )
+ {
+ //
+ // Make sure a RcvAny didn't get to here
+ //
+ ASSERT( (pNCB->ncb_command & ~ASYNCH)== NCBRECV ) ;
+
+ if ( !pConnEle->Orig && fReceive )
+ {
+ prcvCont->usFlags = TDI_RECEIVE_NO_RESPONSE_EXP ;
+ }
+
+ InsertTailList(&pConnEle->RcvHead,
+ &prcvCont->ListEntry);
+
+ return NRC_PENDING ;
+ }
+ else
+ {
+ TDI_REQUEST Request ;
+ UINT cbReceiveLength ;
+ static USHORT usFlags = TDI_RECEIVE_NORMAL ;
+
+ DbgPrint("VxdReceive:A Rcv Buffer posted when data in the transport, InXport= 0x") ;
+ DbgPrintNum( pConnEle->BytesInXport ) ;
+ DbgPrint("\r\n") ;
+
+ pConnEle->OffsetFromStart = 0 ;
+
+ Request.RequestNotifyObject = CompletionRcv ;
+ Request.RequestContext = prcvCont ;
+ Request.Handle.ConnectionContext = pLowerConn->pFileObject ;
+
+ pConnEle->pIrpRcv = NULL ; // Buffer in the transport
+ pLowerConn->StateRcv = FILL_IRP ;
+ RemoveEntryList( &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+
+ cbReceiveLength = min( pNCB->ncb_length,
+ pConnEle->TotalPcktLen-pConnEle->BytesRcvd ) ;
+
+ //
+ // Don't pass zero length buffers to the transport
+ //
+ if ( !cbReceiveLength )
+ {
+ CompletionRcv( prcvCont, STATUS_SUCCESS, 0 ) ;
+ return NRC_GOODRET ;
+ }
+
+ //
+ // if it's an incoming session and this is a receive (as opp. to
+ // receive-any) then give transport a hint that there is no response
+ // coming back (trying to solve the raw-write-to-smb-server-perf problem)
+ //
+ if ( !pConnEle->Orig && fReceive )
+ {
+ usFlags = TDI_RECEIVE_NO_RESPONSE_EXP ;
+ }
+
+ status = TdiVxdReceive( &Request,
+ &usFlags,
+ &cbReceiveLength,
+ &prcvCont->ndisBuff ) ;
+
+ if ( status == STATUS_PENDING )
+ return NRC_PENDING ;
+
+ //
+ // Should always get pending unless a real error occurs
+ //
+ if ( !NT_SUCCESS(status) )
+ {
+ DbgPrint("VxdReceive - TdiReceive failed, error 0x") ;
+ DbgPrintNum( status ) ;
+ DbgPrint("\r\n") ;
+ CTEIoComplete( pNCB, status, 0 ) ;
+ }
+ }
+ }
+ else
+ return NRC_NORESOURCES ;
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdHangup
+
+ SYNOPSIS: Sets up a session Hangup
+
+ ENTRY: pDeviceContext -
+ pNCB - NCB that contains Hangup command
+
+ RETURNS:
+
+ NOTES: The code is similar to VxdDisconnectHandler. If this
+ changes, the VxdDisconnectHandler will probably have to
+ change
+
+ HISTORY:
+ Johnl 12-Jul-1993 Created
+
+********************************************************************/
+
+NCBERR VxdHangup( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ TDI_STATUS tdistatus ;
+ tCONNECTELE * pConnEle ;
+ NCBERR errNCB ;
+ TDI_REQUEST Request ;
+ ULONG TimeOut = DISCONNECT_TIMEOUT ;
+ tCLIENTELE * pClientEle ;
+ tLOWERCONNECTION * pLowerConn;
+
+ if ( errNCB = VxdFindConnectElement( pDeviceContext,
+ pNCB,
+ &pConnEle ))
+ {
+ //
+ // If the session was already closed but the client hasn't been
+ // notified, notify them now
+ //
+ if ( errNCB == NRC_SCLOSED )
+ {
+ CTEIoComplete( pNCB, STATUS_SUCCESS, 0 ) ;
+ errNCB = NRC_GOODRET ;
+ }
+
+ return errNCB ;
+ }
+
+ ASSERT( (pConnEle->Verify == NBT_VERIFY_CONNECTION) ||
+ (pConnEle->Verify == NBT_VERIFY_CONNECTION_DOWN)) ;
+
+ if ( tdistatus = VxdCompleteSessionNcbs( pDeviceContext, pConnEle ) )
+ {
+ DbgPrint("VxdHangup: Error return from VxdCompleteSessionNcbs\r\n") ;
+ }
+
+ if ( pClientEle = pConnEle->pClientEle )
+ {
+ ASSERT( pClientEle->Verify == NBT_VERIFY_CLIENT ||
+ pClientEle->Verify == NBT_VERIFY_CLIENT_DOWN ) ;
+ }
+
+ pLowerConn = pConnEle->pLowerConnId ;
+ if ( pLowerConn &&
+ (pLowerConn->fOnPartialRcvList == TRUE) &&
+ pLowerConn->StateRcv == PARTIAL_RCV )
+ {
+ RemoveEntryList( &pLowerConn->PartialRcvList ) ;
+ pLowerConn->fOnPartialRcvList = FALSE;
+ InitializeListHead(&pLowerConn->PartialRcvList);
+ }
+
+ Request.Handle.ConnectionContext = pConnEle ;
+ tdistatus = NbtDisconnect( &Request,
+ &TimeOut,
+ TDI_DISCONNECT_RELEASE,
+ NULL,
+ NULL,
+ NULL ) ;
+ if ( tdistatus && tdistatus != TDI_PENDING )
+ {
+ DbgPrint("VxdHangup: Warning: NbtDisconnect returned error\r\n") ;
+ }
+
+ tdistatus = NbtCloseConnection( &Request,
+ NULL,
+ pDeviceContext,
+ NULL ) ;
+ if ( tdistatus && tdistatus != TDI_PENDING )
+ {
+ DbgPrint("VxdHangup: Warning: NbtCloseConnection returned error\r\n") ;
+ }
+
+ tdistatus = NbtDisassociateAddress( &Request ) ;
+ if ( tdistatus )
+ {
+ DbgPrint("VxdHangup: NbtDisassociateAddress returned 0x") ;
+ DbgPrintNum( tdistatus ) ; DbgPrint("\r\n") ;
+ }
+
+ REQUIRE( NBUnregister( pDeviceContext, pNCB->ncb_lsn, NB_SESSION )) ;
+
+ //
+ // If this name has been deleted but there were active sessions, check
+ // to see if this is the last session, if so, delete the name
+ //
+
+ if ( pClientEle &&
+ pClientEle->fDeregistered &&
+ !ActiveSessions(pClientEle) )
+ {
+ UCHAR NameNum ;
+ if ( !VxdFindNameNum( pDeviceContext, pClientEle->pAddress, &NameNum ))
+ {
+ (void) VxdCleanupAddress( pDeviceContext,
+ NULL,
+ pClientEle,
+ NameNum,
+ TRUE ) ;
+ }
+ }
+
+ CTEIoComplete( pNCB, STATUS_SUCCESS, 0 ) ;
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdListen
+
+ SYNOPSIS: Sets up a session listen
+
+ ENTRY: pDeviceContext -
+ pNCB - NCB that contains listen command
+
+ RETURNS:
+
+ NOTES: Before we can do the listen we must first open the
+ connection and associate the address.
+
+ The reserve field of the NCB is used as a SESS_SETUP_CONTEXT
+ structure
+
+ HISTORY:
+ Johnl 14-May-1993 Created
+
+********************************************************************/
+
+NCBERR VxdListen( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status;
+ NCBERR errNCB ;
+ TDI_REQUEST Request;
+ PSESS_SETUP_CONTEXT pSessSetupContext = NULL ;
+
+ if ( errNCB = VxdInitSessionSetup( pDeviceContext,
+ &Request,
+ &pSessSetupContext,
+ pNCB ))
+ {
+ return errNCB ;
+ }
+
+ status = NbtListen( &Request,
+ TDI_QUERY_ACCEPT,
+ *pNCB->ncb_callname != '*' ?
+ pSessSetupContext->pRequestConnect : NULL,
+ pSessSetupContext->pReturnConnect,
+ pNCB
+ );
+
+ if ( !NT_SUCCESS( status ) )
+ {
+ VxdTearDownSession( pDeviceContext,
+ Request.Handle.ConnectionContext,
+ pSessSetupContext,
+ NULL ) ;
+ }
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdOpenName
+
+ SYNOPSIS: Creates an Address object in response to AddName or
+ AddGroupName.
+
+ ENTRY: pDeviceContext - Device name is being added to
+ pNCB - NCB AddName submission
+
+ RETURNS: STATUS_SUCCESS if successful, error code otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 20-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdOpenName( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ NTSTATUS status ;
+ TDI_REQUEST tdiRequest ;
+ TDI_ADDRESS_NETBIOS tdiaddr ;
+
+ if ( pNCB->ncb_name[0] == '*' ||
+ pNCB->ncb_name[0] == '\0' )
+ {
+ return NRC_NOWILD ;
+ }
+
+ //
+ // Fill in the TDI structures appropriately
+ //
+ switch ( pNCB->ncb_command & ~ASYNCH )
+ {
+ case NCBADDGRNAME:
+ tdiaddr.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP ;
+ break ;
+
+ case NCBADDNAME:
+ tdiaddr.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE ;
+ break ;
+
+ default:
+ ASSERTMSG("VxdOpenName: Unexpected command type!\n", FALSE ) ;
+ return NRC_SYSTEM ;
+ }
+
+ CTEMemCopy( tdiaddr.NetbiosName,
+ pNCB->ncb_name,
+ sizeof(pNCB->ncb_name) ) ;
+
+ status = NbtOpenAddress( &tdiRequest,
+ &tdiaddr,
+ pDeviceContext->IpAddress,
+ NULL, // Security descriptor
+ pDeviceContext,
+ pNCB ) ;
+ if ( NT_SUCCESS( status ))
+ {
+ //
+ // Set our event handler to catch "Receive Any" and "Receve
+ // Any From Any" NCBs
+ //
+ REQUIRE( !NbtSetEventHandler( (tCLIENTELE*)tdiRequest.Handle.AddressHandle,
+ TDI_EVENT_RECEIVE,
+ ReceiveAnyHandler,
+ (tCLIENTELE*)tdiRequest.Handle.AddressHandle )) ;
+ //
+ // Set an event handler to cleanup up Netbios specific stuff on
+ // disconnect
+ //
+ REQUIRE( !NbtSetEventHandler( (tCLIENTELE*)tdiRequest.Handle.AddressHandle,
+ TDI_EVENT_DISCONNECT,
+ VxdDisconnectHandler,
+ (tCLIENTELE*)tdiRequest.Handle.AddressHandle)) ;
+ }
+
+ //
+ // If we open a non-unique name twice (such as a group name) then
+ // NbtOpenAddress doesn't complete the IRP it just returns success.
+ //
+ if ( status == TDI_SUCCESS )
+ {
+ CTEIoComplete( pNCB, status, (ULONG) tdiRequest.Handle.AddressHandle ) ;
+ }
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+
+/*******************************************************************
+
+ NAME: VxdCloseName
+
+ SYNOPSIS: Called in response to a Netbios Delete Name request
+
+ ENTRY: pDeviceContext - Device name should be deleted from
+ pNCB - Netbios Delete name submission
+
+ RETURNS: STATUS_SUCCESS if successful, error code otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 23-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdCloseName( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ tCLIENTELE * pClientEle ;
+ TDI_STATUS tdistatus ;
+ UCHAR NameNum ;
+ NCBERR errNCB ;
+
+
+ if ( pNCB->ncb_name[0] == '*' ||
+ pNCB->ncb_name[0] == '\0' )
+ {
+ return NRC_NOWILD ;
+ }
+
+ if ( errNCB = VxdNameToClient( pDeviceContext,
+ pNCB->ncb_name,
+ &NameNum,
+ &pClientEle ))
+ {
+ return errNCB ;
+ }
+
+ //
+ // If any sessions are open on this name, delay deletion till last name is
+ // closed
+ //
+ if ( ActiveSessions( pClientEle ) )
+ {
+ VxdCleanupAddress( pDeviceContext, pNCB, pClientEle, NameNum, FALSE ) ;
+ CTEIoComplete( pNCB, STATUS_NRC_ACTSES, 0 ) ;
+ return NRC_GOODRET ;
+ }
+
+ //
+ // No open sessions so blow away the name
+ //
+ return VxdCleanupAddress( pDeviceContext, pNCB, pClientEle, NameNum, TRUE ) ;
+}
+
+/*******************************************************************
+
+ NAME: ActiveSessions
+
+ SYNOPSIS: Returns TRUE if pClientEle has any active sessions
+
+ ENTRY: pClientEle - Client element to check
+
+********************************************************************/
+
+BOOL ActiveSessions( tCLIENTELE * pClientEle )
+{
+ PLIST_ENTRY pHead, pEntry ;
+
+ pHead = &pClientEle->ConnectActive ;
+ pEntry = pClientEle->ConnectActive.Flink ;
+ while ( pHead != pEntry )
+ {
+ tCONNECTELE * pConnEle = CONTAINING_RECORD( pEntry, tCONNECTELE, Linkage ) ;
+
+ if ( pConnEle->state > NBT_ASSOCIATED )
+ {
+ return TRUE ;
+ }
+
+ pEntry = pEntry->Flink ;
+ }
+
+ return FALSE ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCleanupAddress
+
+ SYNOPSIS: Prepares a name for deletion and optionally deletes it
+
+ ENTRY: pDeviceContext - Adapter we are dealing with
+ pNCB - Delete name NCB
+ pClientEle - Client of address element to delete
+ NameNum - Name number in table we are deleting
+ fDeleteAddress - TRUE if address should be deleted
+
+ EXIT: The address element will be marked as deregistered and all
+ non-session NCBs will be completed. The address element
+ may optionally be deleted also.
+
+ NOTES: This routine will complete pNCB as appropriate.
+
+ HISTORY:
+ Johnl 22-Sep-1993 Created
+
+********************************************************************/
+
+NCBERR VxdCleanupAddress( tDEVICECONTEXT * pDeviceContext,
+ NCB * pNCB,
+ tCLIENTELE * pClientEle,
+ UCHAR NameNum,
+ BOOL fDeleteAddress )
+{
+ TDI_REQUEST Request ;
+ NCBERR errNCB ;
+ tCLIENTELE * pClientEleBcast ;
+ TDI_STATUS tdistatus ;
+ USHORT NameType ;
+ PLIST_ENTRY pHead, pEntry ;
+ PLIST_ENTRY pNextEntry;
+ tLISTENREQUESTS * pListen ;
+ PRCV_CONTEXT prcvCont ;
+ tRCVELE * prcvEle ;
+
+ pClientEle->fDeregistered = TRUE ;
+
+ //
+ // Delete all outstanding listens on this name
+ //
+ while ( !IsListEmpty( &pClientEle->ListenHead ))
+ {
+ pEntry = RemoveHeadList( &pClientEle->ListenHead ) ;
+ pListen = CONTAINING_RECORD( pEntry, tLISTENREQUESTS, Linkage ) ;
+ CTEIoComplete( pListen->pIrp, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ CTEMemFree( pListen ) ;
+ }
+
+ //
+ // Delete all outstanding datagram receives on this name
+ //
+ while ( !IsListEmpty( &pClientEle->RcvDgramHead ))
+ {
+ pEntry = RemoveHeadList( &pClientEle->RcvDgramHead ) ;
+ prcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+ CTEIoComplete( prcvEle->pIrp, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ CTEMemFree( prcvEle ) ;
+ }
+
+ //
+ // Delete all outstanding datagram broadcast receives on this name number
+ //
+ errNCB = VxdFindClientElement( pDeviceContext,
+ 0,
+ &pClientEleBcast,
+ CLIENT_BC ) ;
+
+ if ( !errNCB )
+ {
+ //
+ // Scan the NCBs looking for a receive on this name number
+ //
+ pHead = &pClientEleBcast->RcvDgramHead ;
+ pEntry = pClientEleBcast->RcvDgramHead.Flink ;
+
+ while ( pEntry != pHead )
+ {
+ prcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+ pNextEntry = pEntry->Flink ;
+ if ( ((NCB*)prcvEle->pIrp)->ncb_num == NameNum )
+ {
+ RemoveEntryList( pEntry ) ;
+ CTEIoComplete( prcvEle->pIrp, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ CTEMemFree( prcvEle ) ;
+ }
+ pEntry = pNextEntry ;
+ }
+ }
+
+
+ //
+ // Delete all outstanding Receive Anys on this name
+ //
+ while ( !IsListEmpty( &pClientEle->RcvAnyHead ))
+ {
+ pEntry = RemoveHeadList( &pClientEle->RcvAnyHead ) ;
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+ CTEIoComplete( prcvCont->pNCB, STATUS_NETWORK_NAME_DELETED, 0 ) ;
+ }
+
+ tdistatus = TDI_SUCCESS;
+ if ( fDeleteAddress )
+ {
+ Request.Handle.ConnectionContext = pClientEle ;
+ tdistatus = NbtCloseAddress( &Request,
+ NULL, //&RequestStatus,
+ pDeviceContext,
+ pNCB ) ;
+
+ if ( (tdistatus != TDI_PENDING) && pNCB )
+ CTEIoComplete( pNCB, tdistatus, 0 ) ;
+
+ REQUIRE( NBUnregister( pDeviceContext, NameNum, NB_NAME )) ;
+
+ DbgPrint("VxdCloseName: NBUnregistered:NameNum = 0x") ;
+ DbgPrintNum( NameNum ) ;
+ DbgPrint(" ClientEle = 0x") ;
+ DbgPrintNum( pClientEle ) ;
+ DbgPrint("\r\n") ;
+
+ if ( !NT_SUCCESS( tdistatus ))
+ {
+ DbgPrint("VxdCloseName: NbtCloseAddress failed with status 0x") ;
+ DbgPrintNum( tdistatus ) ; DbgPrint("\r\n") ;
+ }
+ }
+
+ return MapTDIStatus2NCBErr( tdistatus ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdAccept
+
+ SYNOPSIS: Accepts an indicated listen
+
+ ENTRY: pConnectElem - Upper part of connection we're about to
+ setup
+ pNCB - Original Listen request
+
+ RETURNS: TDI_SUCCESS if successful error code otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 27-May-1993 Created
+
+********************************************************************/
+
+TDI_STATUS VxdAccept( tCONNECTELE * pConnectElem, NCB * pNCB )
+{
+ TDI_REQUEST Request ;
+ PSESS_SETUP_CONTEXT pSessSetupCont = (PSESS_SETUP_CONTEXT) pNCB->ncb_reserve ;
+ TDI_STATUS status ;
+
+ Request.Handle.ConnectionContext = pConnectElem ;
+
+ status = NbtAccept( &Request,
+ pSessSetupCont->pRequestConnect,
+ pSessSetupCont->pReturnConnect,
+ NULL ) ;
+ if ( !NT_SUCCESS(status) )
+ {
+ DbgPrint( "VxdAccept: NbtAccept returned " ) ;
+ DbgPrintNum( status ) ;
+ DbgPrint("\r\n") ;
+ }
+
+ //
+ // It's OK if the accept is pending because it's just the
+ // session setup acknowledgement
+ //
+ if ( status == TDI_PENDING )
+ status = TDI_SUCCESS ;
+
+ return status ;
+}
+
+/*******************************************************************
+
+ NAME: VxdAdapterStatus
+
+ SYNOPSIS: Gets the requested adapter status
+
+ ENTRY: pDeviceContext - Adapter status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES:
+
+ HISTORY:
+ Johnl 10-Aug-1993 Created
+
+********************************************************************/
+
+NCBERR VxdAdapterStatus( tDEVICECONTEXT * pDeviceContext,
+ NCB * pNCB,
+ ULONG Ipaddr
+ )
+{
+ TDI_STATUS status ;
+ PADAPTER_STATUS pAdapterStatus ;
+ ULONG ActualSize;
+ ULONG Size = pNCB->ncb_length ;
+
+ //
+ // Ipaddr will always be 0 except in one case: if we came here
+ // via nbtstat -A
+ //
+ if ( !Ipaddr && *pNCB->ncb_callname == '*' )
+ {
+ //
+ // Get the local adapter status
+ //
+ DbgPrint("VxdAdapterStatus: AStat for local (*)\r\n") ;
+ status = NbtQueryAdapterStatus( pDeviceContext,
+ &pAdapterStatus,
+ &Size ) ;
+ if ( !status || status == TDI_BUFFER_OVERFLOW )
+ {
+ ActualSize = min( pNCB->ncb_length, Size ) ;
+ CTEMemCopy( pNCB->ncb_buffer,
+ pAdapterStatus,
+ ActualSize) ;
+ pNCB->ncb_length = ActualSize;
+
+ CTEFreeMem( pAdapterStatus ) ;
+ CTEIoComplete( pNCB, status, 0 ) ;
+
+ //
+ // Return a successful status (buffer overflow denoted
+ // in NCB)
+ //
+ status = NRC_GOODRET ;
+ }
+ }
+ else
+ {
+
+ ULONG IpAddrsList[2];
+
+ IpAddrsList[0] = Ipaddr;
+ IpAddrsList[1] = 0;
+
+ status = NbtSendNodeStatus( pDeviceContext,
+ pNCB->ncb_callname,
+ pNCB,
+ IpAddrsList,
+ 0,
+ NodeStatusDone);
+ }
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdFindName
+
+ SYNOPSIS: Gets the requested adapter status
+
+ ENTRY: pDeviceContext - Adapter status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES:
+
+ HISTORY:
+ Johnl 04-Oct-1993 Created
+
+********************************************************************/
+
+NCBERR VxdFindName( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ TDI_STATUS status ;
+ TDI_CONNECTION_INFORMATION RequestInfo ;
+
+ DbgPrint("VxdFindName: Entered\r\n") ;
+ InitNBTDIConnectInfo( &RequestInfo, &tanb_global, pNCB->ncb_callname ) ;
+ status = NbtQueryFindName( &RequestInfo,
+ pDeviceContext,
+ pNCB,
+ FALSE ) ;
+
+ if ( status == STATUS_SUCCESS )
+ {
+ CTEIoComplete( pNCB, STATUS_SUCCESS, 0xffffffff ) ;
+ return STATUS_SUCCESS ;
+ }
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+/*******************************************************************
+
+ NAME: VxdSessionStatus
+
+ SYNOPSIS: Gets the requested Session status
+
+ ENTRY: pDeviceContext - Session status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES: VxdCopySessionStatus will automatically complete the NCB
+ if the buffer overflows. Otherwise we will.
+
+ HISTORY:
+ Johnl 23-Aug-1993 Created
+
+********************************************************************/
+
+NCBERR VxdSessionStatus( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ TDI_STATUS status = STATUS_SUCCESS ;
+ PSESSION_HEADER pSessionHeader = (PSESSION_HEADER) pNCB->ncb_buffer ;
+ PSESSION_BUFFER pSessionBuff ;
+ ULONG RemainingSize = pNCB->ncb_length ;
+ tNAMEADDR * pNameAddr = NULL ;
+ tCLIENTELE * pClientEle = NULL ;
+ tCLIENTELE * pClientEleBcast = NULL ;
+ USHORT NameType ;
+ PLIST_ENTRY pEntry ;
+ UCHAR i ;
+ NCBERR errNCB ;
+
+ if ( RemainingSize < sizeof(SESSION_HEADER) )
+ {
+ CTEIoComplete( pNCB, STATUS_INVALID_BUFFER_SIZE, 0 ) ;
+ return NRC_GOODRET ;
+ }
+
+ pSessionHeader->sess_name = 0 ;
+ pSessionHeader->num_sess = 0 ;
+ pSessionHeader->rcv_dg_outstanding = 0 ;
+ pSessionHeader->rcv_any_outstanding = 0 ;
+
+ //
+ // For broadcast datagram statistics
+ //
+ errNCB = VxdFindClientElement( pDeviceContext,
+ 0,
+ &pClientEleBcast,
+ CLIENT_BC ) ;
+ if ( errNCB )
+ return errNCB ;
+
+ //
+ // Get all sessions?
+ //
+ if ( pNCB->ncb_name[0] == '*' )
+ {
+ for ( i = 1 ; i <= pDeviceContext->cMaxSessions ; i++ )
+ {
+ if ( pDeviceContext->pSessionTable[i] != NULL )
+ {
+ pClientEle = pDeviceContext->pSessionTable[i]->pClientEle ;
+
+ //
+ // Both normal receives and broadcast receives are
+ // kept on the same list
+ //
+ COUNT_ELEMENTS( pClientEle->RcvDgramHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ COUNT_ELEMENTS( pClientEle->RcvAnyHead,
+ pSessionHeader->rcv_any_outstanding ) ;
+ }
+ }
+
+ //
+ // Only one broadcast client element per adapter
+ //
+ COUNT_ELEMENTS( pClientEleBcast->RcvDgramHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ COUNT_ELEMENTS( pDeviceContext->RcvDGAnyFromAnyHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ pSessionHeader->sess_name = 0xff ;
+
+ RemainingSize -= sizeof( SESSION_HEADER ) ;
+ pSessionBuff = (PSESSION_BUFFER) (pSessionHeader + 1) ;
+
+ //
+ // From this device context, traverse all of the Address elements
+ // and all of its Client elements and all of its Connect Elements
+ //
+ for ( pEntry = NbtConfig.AddressHead.Flink ;
+ pEntry != &NbtConfig.AddressHead && !status ;
+ pEntry = pEntry->Flink )
+ {
+ PLIST_ENTRY pEntryClient ;
+ tADDRESSELE * pAddrEle = CONTAINING_RECORD( pEntry,
+ tADDRESSELE,
+ Linkage ) ;
+ ASSERT( pAddrEle->Verify == NBT_VERIFY_ADDRESS ) ;
+
+ //
+ // Only get addresses for this adapter
+ //
+ if ( pAddrEle->pDeviceContext != pDeviceContext )
+ continue ;
+
+ for ( pEntryClient = pAddrEle->ClientHead.Flink ;
+ pEntryClient != &pAddrEle->ClientHead ;
+ pEntryClient = pEntryClient->Flink )
+ {
+ tCLIENTELE * pClientEle = CONTAINING_RECORD( pEntryClient,
+ tCLIENTELE,
+ Linkage ) ;
+ PLIST_ENTRY pEntryConn ;
+ ASSERT( pClientEle->Verify == NBT_VERIFY_CLIENT ||
+ pClientEle->Verify == NBT_VERIFY_CLIENT_DOWN ) ;
+
+ if (!VxdCopySessionStatus( pDeviceContext,
+ pClientEle,
+ pSessionHeader,
+ &pSessionBuff,
+ &RemainingSize ))
+ {
+ status = STATUS_BUFFER_OVERFLOW ;
+ break ;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( errNCB = VxdNameToClient( pDeviceContext,
+ pNCB->ncb_name,
+ &pSessionHeader->sess_name,
+ &pClientEle ))
+ {
+ return errNCB ;
+ }
+
+ COUNT_ELEMENTS( pClientEle->RcvDgramHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ COUNT_ELEMENTS( pClientEleBcast->RcvDgramHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ COUNT_ELEMENTS( pDeviceContext->RcvDGAnyFromAnyHead,
+ pSessionHeader->rcv_dg_outstanding ) ;
+
+ COUNT_ELEMENTS( pClientEle->RcvAnyHead,
+ pSessionHeader->rcv_any_outstanding ) ;
+
+ RemainingSize -= sizeof( SESSION_HEADER ) ;
+ pSessionBuff = (PSESSION_BUFFER) (pSessionHeader + 1) ;
+ if ( !VxdCopySessionStatus( pDeviceContext,
+ pClientEle,
+ pSessionHeader,
+ &pSessionBuff,
+ &RemainingSize ))
+ {
+ status = STATUS_BUFFER_OVERFLOW ;
+ }
+ }
+
+ CTEIoComplete( pNCB,
+ status,
+ sizeof(SESSION_HEADER) +
+ pSessionHeader->num_sess * sizeof(SESSION_BUFFER) ) ;
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCopySessionStatus
+
+ SYNOPSIS: Copies all of the sessions associated with pClientEle
+
+ ENTRY: pDeviceContext - Adapter to use
+ pClientEle - Client to retrieve all sessions for
+ pSessionHeader - Session status header
+ pSessionBuff - Pointer to beginning of session buffers
+ pRemainingSize - Remaining size of buffer
+
+ RETURNS: TRUE if all session information was transferred,
+ FALSE if we ran out of buffer space
+
+ NOTES:
+
+ HISTORY:
+ Johnl 23-Aug-1993 Created
+
+********************************************************************/
+
+BOOL VxdCopySessionStatus( tDEVICECONTEXT * pDeviceContext,
+ tCLIENTELE * pClientEle,
+ PSESSION_HEADER pSessionHeader,
+ PSESSION_BUFFER * ppSessionBuff,
+ ULONG * pRemainingSize )
+{
+ PLIST_ENTRY pEntryConn ;
+ tCONNECTELE * pConnectEle ;
+
+ for ( pEntryConn = pClientEle->ConnectActive.Flink ;
+ pEntryConn != &pClientEle->ConnectActive ;
+ pEntryConn = pEntryConn->Flink )
+ {
+ PLIST_ENTRY pEntry ;
+ BOOL fFillRemote = FALSE ;
+ pConnectEle = CONTAINING_RECORD( pEntryConn,
+ tCONNECTELE,
+ Linkage ) ;
+ ASSERT( pConnectEle->Verify == NBT_VERIFY_CONNECTION ||
+ pConnectEle->Verify == NBT_VERIFY_CONNECTION_DOWN ) ;
+
+ if ( *pRemainingSize < sizeof(SESSION_BUFFER) )
+ {
+ return FALSE ;
+ }
+
+ *pRemainingSize -= sizeof(SESSION_BUFFER) ;
+ pSessionHeader->num_sess++ ;
+ (*ppSessionBuff)->rcvs_outstanding = 0 ;
+ (*ppSessionBuff)->sends_outstanding = 0 ; // Always 0
+ REQUIRE( !VxdFindLSN( pDeviceContext, pConnectEle, &(*ppSessionBuff)->lsn )) ;
+
+ COUNT_ELEMENTS( pConnectEle->RcvHead,
+ (*ppSessionBuff)->rcvs_outstanding ) ;
+
+ //
+ // Set the session state
+ //
+ switch ( pConnectEle->state )
+ {
+ case NBT_CONNECTING: // establishing Transport connection
+ if ( pConnectEle->Orig )
+ (*ppSessionBuff)->state = CALL_PENDING ;
+ else
+ (*ppSessionBuff)->state = LISTEN_OUTSTANDING ;
+ break ;
+
+ case NBT_SESSION_INBOUND: // waiting for a session request after tcp connectio
+ case NBT_SESSION_WAITACCEPT: // waiting for accept after a listen has been satis
+ (*ppSessionBuff)->state = LISTEN_OUTSTANDING ;
+ break ;
+
+ case NBT_SESSION_OUTBOUND: // waiting for a session response after tcp connecti
+ fFillRemote = TRUE ;
+ (*ppSessionBuff)->state = CALL_PENDING ;
+
+ case NBT_SESSION_UP: // got positive response
+ fFillRemote = TRUE ;
+ (*ppSessionBuff)->state = SESSION_ESTABLISHED ;
+ break ;
+
+ case NBT_DISCONNECTING: // sent a disconnect down to Tcp, but it hasn't comp
+ (*ppSessionBuff)->state = HANGUP_PENDING;
+ break ;
+
+ case NBT_DISCONNECTED: // a session has been disconnected but not closed wit
+ (*ppSessionBuff)->state = HANGUP_COMPLETE;
+ break ;
+
+ case NBT_IDLE: // Shouldn't be on ConnectActive list
+ case NBT_ASSOCIATED:
+ default:
+ ASSERT( FALSE ) ;
+ (*ppSessionBuff)->state = SESSION_ABORTED ;
+ break ;
+ }
+
+ //
+ // Copy local and/or remote name
+ //
+ CTEMemCopy( (*ppSessionBuff)->local_name,
+ pClientEle->pAddress->pNameAddr->Name,
+ NCBNAMSZ ) ;
+
+ if ( fFillRemote )
+ {
+ CTEMemCopy( (*ppSessionBuff)->remote_name,
+ pConnectEle->RemoteName,
+ NCBNAMSZ ) ;
+ }
+
+ (*ppSessionBuff)++ ;
+ }
+
+ return TRUE ;
+}
+
+/*******************************************************************
+
+ NAME: VxdReset
+
+ SYNOPSIS: Clears out the name tables and completes all outstanding NCBs
+
+ ENTRY: pDeviceContext - Adapter status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES: If a session is active then we have to wait till we disconnect
+ the connection before deleting the name. We keep count of the
+ active sessions and call the VxdResetContinue function after
+ all session disconnects have been completed.
+
+ It is assumed this is made as a "wait" call.
+
+ HISTORY:
+ Johnl 16-Aug-1993 Created
+
+********************************************************************/
+
+NCBERR VxdReset( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ UCHAR i ;
+ TDI_STATUS tdistatus ;
+ PLIST_ENTRY pHead, pEntry ;
+ PRESET_CONTEXT pRstCont = (PRESET_CONTEXT) pNCB->ncb_reserve ;
+
+ pRstCont->cActiveSessions = 0 ;
+ pRstCont->cActiveNames = 0 ;
+ pRstCont->errncb = NRC_GOODRET ;
+
+ //
+ // Kill off all of the Receive any from any NCBs
+ //
+ while ( !IsListEmpty(&pDeviceContext->RcvAnyFromAnyHead))
+ {
+ PRCV_CONTEXT prcvCont ;
+ pEntry = RemoveHeadList( &pDeviceContext->RcvAnyFromAnyHead ) ;
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ CTEIoComplete( prcvCont->pNCB,
+ STATUS_CONNECTION_DISCONNECTED,
+ 0 ) ;
+ }
+
+ //
+ // Kill off all of the Receive any datagrams from any
+ //
+ while ( !IsListEmpty(&pDeviceContext->RcvDGAnyFromAnyHead))
+ {
+ tRCVELE * pRcvEle ;
+ pEntry = RemoveHeadList( &pDeviceContext->RcvDGAnyFromAnyHead ) ;
+ pRcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+ CTEIoComplete( pRcvEle->pIrp,
+ STATUS_NETWORK_NAME_DELETED, // NRC_NAMERR
+ 0 ) ;
+ CTEMemFree( pRcvEle ) ;
+ }
+
+ //
+ // Disconnect all sessions
+ //
+ for ( i = 1 ; i <= pDeviceContext->cMaxSessions ; i++ )
+ {
+ //
+ // This will also prevent any listens from being accepted on the
+ // connection
+ //
+ if ( pDeviceContext->pSessionTable[i] != NULL )
+ {
+ TDI_REQUEST Request ;
+ ULONG TimeOut = DISCONNECT_TIMEOUT ;
+ tCONNECTELE * pConnEle= pDeviceContext->pSessionTable[i] ;
+
+ Request.Handle.ConnectionContext = pConnEle ;
+ pRstCont->cActiveSessions++ ;
+ tdistatus = NbtDisconnect( &Request,
+ &TimeOut,
+ TDI_DISCONNECT_RELEASE,
+ NULL,
+ NULL,
+ pNCB ) ;
+
+ if ( tdistatus != TDI_PENDING )
+ {
+ pRstCont->cActiveSessions-- ;
+ tdistatus = NbtCloseConnection( &Request,
+ NULL,
+ pDeviceContext,
+ NULL ) ;
+ REQUIRE( NBUnregister( pDeviceContext, i, NB_SESSION )) ;
+ }
+ }
+ }
+
+ //
+ // If no active sessions, then go ahead and delete all the names
+ //
+ if ( !pRstCont->cActiveSessions )
+ {
+ pRstCont->cActiveSessions = -1 ;
+ return VxdResetContinue( pDeviceContext, pNCB ) ;
+ }
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdResetContinue
+
+ SYNOPSIS: Finishes the reset after all sessions have been successfully
+ shutdown
+
+ ENTRY: pDeviceContext - Adapter status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES:
+
+ HISTORY:
+ Johnl 16-Aug-1993 Created
+
+********************************************************************/
+
+NCBERR VxdResetContinue( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ UCHAR i ;
+ TDI_STATUS tdistatus ;
+ PLIST_ENTRY pHead, pEntry ;
+ PRESET_CONTEXT pRstCont = (PRESET_CONTEXT) pNCB->ncb_reserve ;
+ PNCB pNCBPerm ;
+
+ DbgPrint("VxdResetContinue entered\r\n") ;
+
+ //
+ // Now that all of the sessions have been disconnected, close each
+ // connection
+ //
+ for ( i = 1 ; i <= pDeviceContext->cMaxSessions ; i++ )
+ {
+ if ( pDeviceContext->pSessionTable[i] != NULL )
+ {
+ TDI_REQUEST Request ;
+ tCONNECTELE * pConnEle = pDeviceContext->pSessionTable[i] ;
+ Request.Handle.ConnectionContext = pConnEle ;
+
+ tdistatus = NbtCloseConnection( &Request,
+ NULL,
+ pDeviceContext,
+ NULL ) ;
+ REQUIRE( NBUnregister( pDeviceContext, i, NB_SESSION )) ;
+ }
+ }
+
+ //
+ // Delete all the names (including the permanent name)
+ //
+ for ( i = 0 ; i <= pDeviceContext->cMaxNames ; i++ )
+ {
+ if ( pDeviceContext->pNameTable[i] != NULL )
+ {
+ TDI_REQUEST Request ;
+
+ Request.Handle.ConnectionContext = pDeviceContext->pNameTable[i] ;
+ pRstCont->cActiveNames++ ;
+
+ tdistatus = NbtCloseAddress( &Request,
+ NULL, //&RequestStatus,
+ pDeviceContext,
+ pNCB ) ;
+ if ( tdistatus != TDI_PENDING )
+ pRstCont->cActiveNames-- ;
+
+ //
+ // Go ahead and remove the name from the table since nobody
+ // will be able to re-register with it since this is a "wait" cmd
+ //
+ REQUIRE( NBUnregister( pDeviceContext, i, NB_NAME )) ;
+
+ }
+ }
+
+ //
+ // Resize the session table If an error occurs, keep the old
+ // session table.
+ //
+ if ( pNCB->ncb_lsn != pDeviceContext->cMaxSessions )
+ {
+ UCHAR MaxSess = (UCHAR) pNCB->ncb_lsn ? pNCB->ncb_lsn : 6 ;
+ PVOID pSess = CTEAllocMem((USHORT)((MaxSess+1)*sizeof(tCONNECTELE*))) ;
+
+ if ( !pSess )
+ {
+ pRstCont->errncb = NRC_NORESOURCES ;
+ }
+ else
+ {
+ CTEFreeMem( pDeviceContext->pSessionTable ) ;
+ pDeviceContext->cMaxSessions = MaxSess ;
+ pDeviceContext->pSessionTable = pSess ;
+ CTEZeroMemory( &pDeviceContext->pSessionTable[0],
+ (pDeviceContext->cMaxSessions+1)*sizeof(tCONNECTELE*) ) ;
+ }
+ }
+
+ //
+ // Set current session/name numbers back to 1
+ //
+ pDeviceContext->iNcbNum = 1 ;
+ pDeviceContext->iLSNum = 1 ;
+
+ //
+ // re-add the permanent name for this adapter, non-fatal if it fails
+ //
+
+
+ if ( !NT_SUCCESS( NbtAddPermanentName( pDeviceContext )))
+ {
+ CDbgPrint( DBGFLAG_ERROR,
+ ("VxdResetContinue: Warning - Failed to add permanent name")) ;
+ }
+
+ if ( !pRstCont->cActiveNames )
+ CTEIoComplete( pNCB, NRC_GOODRET, 0 ) ;
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCancel
+
+ SYNOPSIS: Attempts to cancel the NCB pointed at by ncb_buffer
+
+ ENTRY: pDeviceContext - Adapter status to get
+ pNCB - Pointer to requesting NCB
+
+ EXIT:
+
+ NOTES:
+
+ HISTORY:
+ Johnl 18-Aug-1993 Created
+
+********************************************************************/
+
+NCBERR VxdCancel( tDEVICECONTEXT * pDeviceContext, NCB * pNCB )
+{
+ NCB * pNCBCancelled = (NCB*) pNCB->ncb_buffer ;
+ tCONNECTELE * pConnEle ;
+ tCLIENTELE * pClientEle ;
+ NCBERR errNCB = NRC_GOODRET ;
+ TDI_STATUS tdistatus ;
+ PLIST_ENTRY pHead, pEntry ;
+ USHORT NameType ;
+ tNAMEADDR * pNameAddr ;
+ tLISTENREQUESTS * pListen ;
+ PRCV_CONTEXT prcvCont ; // Used for session receives
+ tRCVELE * prcvEle ; // Used for Datagram receives
+
+ if ( pNCB->ncb_lana_num != pNCBCancelled->ncb_lana_num )
+ {
+ DbgPrint("VxdCancel: Attempt to cancel NCB w/ different lana\r\n") ;
+ return NRC_BRIDGE ;
+ }
+
+ if ( pNCB->ncb_retcode != NRC_PENDING )
+ return NRC_CANOCCR ;
+
+ switch ( pNCBCancelled->ncb_command & ~ASYNCH )
+ {
+ case NCBSEND:
+ case NCBSENDNA:
+ case NCBCHAINSEND:
+ case NCBCHAINSENDNA:
+ case NCBRECV:
+ //
+ // Cancelling a session NCB automatically closes the session
+ //
+ if ( VxdFindConnectElement( pDeviceContext,
+ pNCBCancelled,
+ &pConnEle ))
+ {
+ DbgPrint("VxdCancel: Attempted to cancel send NCB on non-existent session\r\n") ;
+ break ;
+ }
+
+ if ( (pNCBCancelled->ncb_command & ~ASYNCH) == NCBRECV )
+ {
+ errNCB = NRC_CANOCCR ;
+ for ( pEntry = pConnEle->RcvHead.Flink ;
+ pEntry != &pConnEle->RcvHead ;
+ pEntry = pEntry->Flink )
+ {
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ if ( prcvCont->pNCB == pNCBCancelled )
+ {
+ RemoveEntryList( pEntry ) ;
+ CTEIoComplete( prcvCont->pNCB, STATUS_CANCELLED, 0 ) ;
+ errNCB = NRC_GOODRET ;
+ break ;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Sends are immediately submitted to the transport, tell
+ // caller it's too late to cancel. The transport will complete
+ // the NCB when we close the connection below.
+ //
+ errNCB = NRC_CANOCCR ;
+ }
+
+ REQUIRE( !VxdCompleteSessionNcbs( pDeviceContext, pConnEle )) ;
+ VxdTearDownSession( pDeviceContext,
+ pConnEle,
+ NULL,
+ NULL ) ;
+ //
+ // Only remove from table if we've told the client
+ //
+ if ( pConnEle->Flags & NB_CLIENT_NOTIFIED )
+ {
+ REQUIRE( NBUnregister( pDeviceContext,
+ pNCBCancelled->ncb_lsn,
+ NB_SESSION )) ;
+ }
+ break ;
+
+ case NCBCANCEL:
+ errNCB = NRC_CANCEL ; // Can't cancel a cancel
+ break ;
+
+ case NCBLISTEN:
+ //
+ // Lookup the Client Element associated with this name, then scan
+ // the listen NCBs for one that matches the one being cancelled
+ //
+ if ( errNCB = VxdNameToClient( pDeviceContext,
+ pNCBCancelled->ncb_name,
+ NULL,
+ &pClientEle ))
+ {
+ DbgPrint("VxdCancel: Tried to cancel listen on non-existent name\r\n") ;
+ errNCB = NRC_CANOCCR ;
+ break ;
+ }
+
+ errNCB = NRC_CANOCCR ;
+ for ( pEntry = pClientEle->ListenHead.Flink ;
+ pEntry != &pClientEle->ListenHead ;
+ pEntry = pEntry->Flink )
+ {
+ pListen = CONTAINING_RECORD( pEntry, tLISTENREQUESTS, Linkage ) ;
+ if ( pListen->pIrp == pNCBCancelled )
+ {
+ DbgPrint("VxdCancel: Cancelling NCB 0x") ;
+ DbgPrintNum( (ULONG) pNCBCancelled ) ; DbgPrint("\r\n") ;
+ RemoveEntryList( &pListen->Linkage ) ;
+ CTEIoComplete( pNCBCancelled, STATUS_CANCELLED, 0 ) ;
+ CTEMemFree( pListen ) ;
+ errNCB = NRC_GOODRET ;
+ break ;
+ }
+ }
+ break ;
+
+ case NCBCALL:
+ //
+ // Search the ConnectActive list for our NCB and cleanup that
+ // connection
+ //
+ if ( errNCB = VxdNameToClient( pDeviceContext,
+ pNCBCancelled->ncb_name,
+ NULL,
+ &pClientEle ))
+ {
+ DbgPrint("VxdCancel: Tried to cancel call on non-existent name\r\n") ;
+ errNCB = NRC_CANOCCR ;
+ break ;
+ }
+
+ errNCB = NRC_CANOCCR ;
+ for ( pEntry = pClientEle->ConnectActive.Flink ;
+ pEntry != &pClientEle->ConnectActive ;
+ pEntry = pEntry->Flink )
+ {
+ pConnEle = CONTAINING_RECORD( pEntry, tCONNECTELE, Linkage ) ;
+ if ( pConnEle->pIrp == pNCBCancelled )
+ {
+ tDGRAM_SEND_TRACKING * pTracker = (tDGRAM_SEND_TRACKING*)
+ pConnEle->pIrpRcv ;
+
+ //
+ // if it's too late, just say we can't cancel it
+ //
+ if (pConnEle->state >= NBT_SESSION_OUTBOUND)
+ {
+ errNCB = NRC_CANOCCR ;
+ break;
+ }
+
+ //
+ // yes, we can cancel it. we just mark the tracker to say
+ // this call is cancelled: both the original ncb and this
+ // cancel ncb will get completed at some stage.
+ //
+ DbgPrint("VxdCancel: Cancelling NCB 0x") ;
+ DbgPrintNum( (ULONG) pNCBCancelled ) ; DbgPrint("\r\n") ;
+
+ pTracker->Flags |= TRACKER_CANCELLED;
+ pConnEle->pIrpDisc = pNCB;
+
+ return NRC_GOODRET ;
+ }
+ }
+ break ;
+
+ case NCBDGRECV:
+ if ( pNCBCancelled->ncb_num == ANY_NAME )
+ {
+ pHead = &pDeviceContext->RcvDGAnyFromAnyHead ;
+ }
+ else
+ {
+ if ( errNCB = VxdFindClientElement( pDeviceContext,
+ pNCBCancelled->ncb_num,
+ &pClientEle,
+ CLIENT_LOCAL ) )
+ {
+ ASSERT( FALSE ) ;
+ break ;
+ }
+ pHead = &pClientEle->RcvDgramHead ;
+ }
+
+ errNCB = NRC_CANOCCR ;
+ for ( pEntry = pHead->Flink ;
+ pEntry != pHead ;
+ pEntry = pEntry->Flink )
+ {
+ prcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+
+ if ( prcvEle->pIrp == pNCBCancelled )
+ {
+ RemoveEntryList( pEntry ) ;
+ CTEIoComplete( pNCBCancelled, STATUS_CANCELLED, 0 ) ;
+ CTEMemFree( prcvEle ) ;
+ errNCB = NRC_GOODRET ;
+ break ;
+ }
+ }
+ break ;
+
+ case NCBDGRECVBC:
+ //
+ // For receive broadcast datagrams, we have to look through the list
+ // of clients on the Broadcast Address.
+ //
+ errNCB = VxdFindClientElement( pDeviceContext,
+ 0,
+ &pClientEle,
+ CLIENT_BC ) ;
+ if ( !errNCB )
+ {
+ errNCB = NRC_CANOCCR ;
+ for ( pEntry = pClientEle->RcvDgramHead.Flink ;
+ pEntry != &pClientEle->RcvDgramHead ;
+ pEntry = pEntry->Flink )
+ {
+ prcvEle = CONTAINING_RECORD( pEntry, tRCVELE, Linkage ) ;
+ if ( prcvEle->pIrp == pNCBCancelled )
+ {
+ RemoveEntryList( pEntry ) ;
+ CTEMemFree( prcvEle ) ;
+ CTEIoComplete( pNCBCancelled, STATUS_CANCELLED, 0 ) ;
+ errNCB = NRC_GOODRET ;
+ break ;
+ }
+ }
+ }
+ break ;
+
+ case NCBRECVANY:
+ if ( pNCBCancelled->ncb_num == ANY_NAME )
+ pHead = &pDeviceContext->RcvAnyFromAnyHead ;
+ else
+ {
+ if ( errNCB = VxdFindClientElement( pDeviceContext,
+ pNCBCancelled->ncb_num,
+ &pClientEle,
+ CLIENT_LOCAL ) )
+ {
+ ASSERT( FALSE ) ;
+ break ;
+ }
+ pHead = &pClientEle->RcvAnyHead ;
+ }
+
+ errNCB = NRC_CANOCCR ;
+ pEntry = pHead->Flink ;
+ while ( pEntry != pHead )
+ {
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ if ( prcvCont->pNCB == pNCBCancelled )
+ {
+ RemoveEntryList( pEntry ) ;
+ CTEIoComplete( prcvCont->pNCB, STATUS_CANCELLED, 0 ) ;
+ errNCB = NRC_GOODRET ;
+ break ;
+ }
+ pEntry = pEntry->Flink ;
+ }
+ break ;
+
+ default:
+ errNCB = NRC_CANCEL ;
+ }
+
+
+ CTEIoComplete( pNCB, errNCB, 0 ) ;
+
+ //
+ // No, no! Don't touch that ncb after completing it!
+ //
+ //pNCB->ncb_retcode = errNCB ;
+ //pNCB->ncb_cmd_cplt = errNCB ;
+
+ return errNCB ;
+}
+
+/*******************************************************************
+
+ NAME: VxdIoComplete
+
+ SYNOPSIS: Let's the NCB know that all processing is done by setting
+ the command completion fields and calling the post routine
+ if available.
+
+ ENTRY: pirp - Pointer to the NCB to notify that we are done
+ (or NULL if this didn't come from the Netbios I/F
+ status - Status of the completion
+ ulExtra - Extra parameter
+
+ NOTES: This is the procedure that CTEIoComplete maps to and is
+ roughly equivilent to "completing" an IRP.
+
+ HISTORY:
+ Johnl 27-Apr-1993 Created
+
+********************************************************************/
+
+VOID VxdIoComplete( PCTE_IRP pirp,
+ NTSTATUS status,
+ ULONG ulExtra )
+{
+ NCB * pNCB = pirp ;
+ NCBERR errNCB = NRC_GOODRET ;
+ PSESS_SETUP_CONTEXT pSessSetupCont ;
+ BOOL fAsync ;
+ tDEVICECONTEXT * pDeviceContext ;
+ PRESET_CONTEXT pRstCont ;
+ PSEND_CONTEXT pSendCont ;
+ tCONNECTELE * pConnEle ;
+
+ DbgPrint("VxdIoComplete: Completing NCB; Cmd, Addr, TDI status: 0x") ;
+ if ( pNCB )
+ {
+ DbgPrintNum( pNCB->ncb_command ) ;
+ DbgPrint(" 0x") ; DbgPrintNum( (ULONG) pNCB ) ;
+ DbgPrint(" 0x") ; DbgPrintNum( status ) ;
+ DbgPrint("\r\n") ;
+ }
+ else
+ DbgPrint("NULL\r\n") ;
+
+ //
+ // If no NCB to complete then we're done
+ //
+ if ( !pNCB )
+ return ;
+
+ fAsync = !!(pNCB->ncb_command & ASYNCH) ;
+
+ pDeviceContext = GetDeviceContext( pNCB ) ;
+
+ ASSERT(pDeviceContext);
+
+ //
+ // Note that we drop through the below case statement even if an error
+ // occurred because some commands need to free stuff before completing
+ // the NCB.
+ //
+ if ( status != STATUS_SUCCESS &&
+ ( pNCB->ncb_command & ~ASYNCH) != NCBCANCEL )
+ {
+ errNCB = MapTDIStatus2NCBErr( status ) ;
+ }
+
+ //
+ // Fill in any items in the NCB struct if necessary
+ //
+ switch( pNCB->ncb_command & ~ASYNCH )
+ {
+ case NCBRECVANY: // lsn was set when the receive was posted
+ case NCBRECV:
+ FreeRcvContext( *((PRCV_CONTEXT*)&pNCB->ncb_reserve) ) ;
+ if ( errNCB && errNCB != NRC_INCOMP )
+ {
+ break ;
+ }
+
+ ASSERT( ulExtra <= 0xffff ) ;
+ ASSERT( pNCB->ncb_length >= ulExtra ) ;
+ pNCB->ncb_length = (WORD) ulExtra ;
+
+ DbgPrint("\tSetting length to 0x") ;
+ DbgPrintNum( ulExtra ) ;
+ DbgPrint("\r\n") ;
+ break ;
+
+ case NCBSSTAT:
+ case NCBDGRECV:
+ case NCBDGRECVBC:
+ if ( errNCB && errNCB != NRC_INCOMP )
+ break ;
+
+ ASSERT( ulExtra <= 0xffff ) ;
+ ASSERT( pNCB->ncb_length >= ulExtra ) ;
+ pNCB->ncb_length = (WORD) ulExtra ;
+
+ DbgPrint("\tSetting length to 0x") ;
+ DbgPrintNum( ulExtra ) ;
+ DbgPrint("\r\n") ;
+ break ;
+
+ case NCBASTAT:
+ case NCBFINDNAME:
+ if ( errNCB && errNCB != NRC_INCOMP )
+ break ;
+
+ if ( ulExtra != 0xffffffff ) // Means buffer length already set
+ pNCB->ncb_length = (WORD) ulExtra ;
+
+ DbgPrint("\tAStat/Findname length is 0x") ;
+ DbgPrintNum( (ULONG) pNCB->ncb_length ) ;
+ DbgPrint("\r\n") ;
+ break ;
+
+ case NCBSEND:
+ case NCBSENDNA:
+ case NCBCHAINSEND:
+ case NCBCHAINSENDNA:
+ pSendCont = (PSEND_CONTEXT) pNCB->ncb_reserve ;
+ if ( errNCB )
+ {
+ //
+ // Sends are immediately given to the transport, so if a
+ // timeout occurs, we'll first be completed by the timeout
+ // code, then we'll be completed by the transport closing
+ // the connection.
+ //
+
+ if ( errNCB != NRC_CMDTMO &&
+ pSendCont->STO == NCB_TIMED_OUT )
+ {
+ //
+ // The transport has completed this NCB in response to the
+ // Close connection because of a send timeout. Map the
+ // error to timeout and complete back to the client. The
+ // session is dead so don't disconnect it again. The send
+ // has already been removed from the timeout list.
+ //
+ errNCB = NRC_CMDTMO ;
+ }
+ else
+ {
+ BOOL fTimedOutNCB = pSendCont->STO == NCB_TIMED_OUT ;
+
+ //
+ // Remove from timeout list
+ //
+ if ( pSendCont->STO != NCB_INFINITE_TIME_OUT )
+ RemoveEntryList( &pSendCont->ListEntry ) ;
+
+ //
+ // Kill the session
+ //
+ if ( VxdFindConnectElement( pDeviceContext,
+ pNCB,
+ &pConnEle ))
+
+ {
+ //
+ // There maybe multiple sends on this session, only the
+ // first should disconnect
+ //
+ CTEFreeMem( pSendCont->pHdr ) ;
+ DbgPrint("VxdIoComplete: Error occurred on non-existent session\r\n") ;
+ break ;
+ }
+
+ REQUIRE( !VxdCompleteSessionNcbs( pDeviceContext, pConnEle )) ;
+
+ //
+ // Only remove from table if we've told the client
+ //
+ if ( pConnEle->Flags & NB_CLIENT_NOTIFIED )
+ {
+ REQUIRE( NBUnregister( pDeviceContext,
+ pNCB->ncb_lsn,
+ NB_SESSION )) ;
+ }
+
+ VxdTearDownSession( pDeviceContext,
+ pConnEle,
+ NULL,
+ NULL ) ;
+
+ if ( fTimedOutNCB ) // pSendCont may already have been freed
+ {
+ //
+ // The Close Connection above will cause the transport to
+ // complete this send with a session closed error, wait
+ // for that before completing back to the client.
+ //
+ return ;
+ }
+ }
+ }
+ else
+ {
+ if ( pSendCont->STO != NCB_INFINITE_TIME_OUT )
+ RemoveEntryList( &pSendCont->ListEntry ) ;
+ }
+ FreeSessionHdr( pSendCont->pHdr ) ;
+ break ;
+
+ case NCBDGSEND:
+ case NCBDGSENDBC:
+ //
+ // Nothing to do
+ //
+ break ;
+
+ //
+ // Need to set the ncb_num field for the following commands. Note
+ // that the ulExtra parameter will contain a pointer to the address
+ // element that was just added for this name.
+ //
+ case NCBADDNAME:
+ case NCBADDGRNAME:
+ if ( errNCB )
+ break ;
+
+ if ( !NBRegister( pDeviceContext,
+ &pNCB->ncb_num,
+ (tCLIENTELE *) ulExtra,
+ NB_NAME ))
+ {
+ TDI_REQUEST Request ;
+ TDI_STATUS tdistatus ;
+
+ errNCB = NRC_NAMTFUL ;
+ Request.Handle.ConnectionContext = (tCLIENTELE *) ulExtra ;
+ tdistatus = NbtCloseAddress( &Request,
+ NULL, //&RequestStatus,
+ pDeviceContext,
+ NULL ) ;
+ ASSERT( NT_SUCCESS( tdistatus )) ;
+ }
+ else
+ {
+ DbgPrint("\tRegistered Name number ") ;
+ DbgPrintNum( pNCB->ncb_num ) ;
+ DbgPrint(" for Address Element ") ;
+ DbgPrintNum( ulExtra ) ;
+ DbgPrint("\r\n") ;
+ }
+ break ;
+
+#if 0
+ //
+ // Private NBT NCB type for processing the permanent name
+ //
+ case NCBADD_PERMANENT_NAME:
+ CTEFreeMem( pNCB ) ;
+
+ if ( errNCB )
+ {
+ DbgPrint("VxdIoComplete: Failed to add permanent name!\r\n") ;
+ }
+ else
+ {
+ ASSERT( pDeviceContext->pNameTable[0] == NULL ) ;
+ pDeviceContext->pNameTable[0] = (tCLIENTELE *) ulExtra ;
+ }
+ //
+ // Don't do any further processing of this NCB. Not only did
+ // we just free it, nobody is looking for it.
+ //
+ return ;
+#endif
+
+ case NCBCALL:
+ case NCBLISTEN:
+ pSessSetupCont = (PSESS_SETUP_CONTEXT) pNCB->ncb_reserve ;
+
+ if ( errNCB )
+ {
+ VxdTearDownSession( pDeviceContext,
+ pSessSetupCont->pConnEle,
+ pSessSetupCont,
+ NULL ) ;
+ break ;
+ }
+
+ //
+ // Put the connection in our LSN table and copy out the connecting
+ // name if necessary
+ //
+ if ( !NBRegister( pDeviceContext,
+ &pNCB->ncb_lsn,
+ (tCONNECTELE *) ulExtra,
+ NB_SESSION ))
+ {
+ VxdTearDownSession( pDeviceContext,
+ (tCONNECTELE *) ulExtra,
+ NULL,
+ NULL ) ;
+ errNCB = NRC_LOCTFUL ;
+ }
+ else
+ {
+ tCONNECTELE * pConnEle = (tCONNECTELE*) ulExtra ;
+
+ //
+ // Were we listenning for '*'? If so, copy out the connecting
+ // name.
+ //
+ if ( pSessSetupCont->fIsWorldListen )
+ {
+ DbgPrint( "VxdIoComplete: World listen accepted \"" ) ;
+ DbgPrint( pConnEle->RemoteName ) ;
+ DbgPrint("\" for connection endpoint\r\n") ;
+
+ CTEMemCopy( pNCB->ncb_callname,
+ pConnEle->RemoteName,
+ NCBNAMSZ ) ;
+ }
+
+ ((tCONNECTELE *)ulExtra)->RTO = pNCB->ncb_rto ;
+ ((tCONNECTELE *)ulExtra)->STO = pNCB->ncb_sto ;
+ ((tCONNECTELE *)ulExtra)->Flags = 0 ;
+
+ //
+ // Don't delete the connection element until the client has been
+ // notified that the connection is down
+ //
+ ((tCONNECTELE *)ulExtra)->RefCount++ ;
+
+ DbgPrint("\tRegistered Session number ") ;
+ DbgPrintNum( pNCB->ncb_lsn ) ;
+ DbgPrint(" for Connection Element ") ;
+ DbgPrintNum( (ULONG) pConnEle ) ;
+ DbgPrint("\r\n") ;
+ }
+
+ FreeSessSetupContext( pSessSetupCont ) ;
+
+ //
+ // If we're in WAITACCEPT, then this is a Listen that needs to
+ // be accepted
+ //
+ if ( ((tCONNECTELE *)ulExtra)->state == NBT_SESSION_WAITACCEPT )
+ {
+ //
+ // Accept the connection
+ //
+ VxdAccept( (tCONNECTELE *) ulExtra, NULL ) ;
+ }
+ break ;
+
+ case NCBRESET:
+ pRstCont = (PRESET_CONTEXT) pNCB->ncb_reserve ;
+ if ( pRstCont->cActiveSessions != -1 ||
+ pRstCont->cActiveNames )
+ {
+ DbgPrint("VxdIoComplete: Disconnect/Name de-reg completed from Reset, remaining disconnects, names: ") ;
+ DbgPrintNum( pRstCont->cActiveSessions ) ;
+ DbgPrintNum( pRstCont->cActiveNames ) ; DbgPrint("\r\n") ;
+
+ //
+ // Only complete the Reset NCB after all session have been
+ // disconnected and the names have been released on the network
+ //
+ if ( pRstCont->cActiveSessions != -1 )
+ {
+ if ( --pRstCont->cActiveSessions == 0 )
+ {
+ //
+ // Starts the name deletion process
+ //
+ pRstCont->cActiveSessions = -1 ;
+ VxdResetContinue( pDeviceContext, pNCB ) ;
+ }
+
+ return ;
+ }
+
+ if ( --pRstCont->cActiveNames != 0 )
+ {
+ return ;
+ }
+ }
+
+ if ( !errNCB )
+ errNCB = pRstCont->errncb ;
+
+ // Fall through
+
+ case NCBUNLINK:
+ pNCB->ncb_retcode = errNCB ;
+ pNCB->ncb_cmd_cplt = errNCB ;
+ goto SkipPost ;
+
+ case NCBCANCEL:
+ pNCB->ncb_retcode = errNCB ;
+ pNCB->ncb_cmd_cplt = errNCB ;
+ break;
+
+ case NCBHANGUP:
+ case NCBDELNAME:
+ case NCBTRACE:
+ break ;
+
+ default:
+ DbgPrint("VxdIoComplete: Unexpected NCB command: 0x") ;
+ DbgPrintNum( pNCB->ncb_command ) ; DbgPrint("\r\n") ;
+ break ;
+ }
+
+ if ( pNCB->ncb_retcode == NRC_PENDING )
+ {
+ pNCB->ncb_retcode = errNCB ;
+ pNCB->ncb_cmd_cplt = errNCB ;
+ }
+ else
+ {
+ if ( (pNCB->ncb_command & ~ASYNCH) != NCBCANCEL )
+ {
+ CTEPrint("VxdIoComplete: ncb_retcode already set!\r\n") ;
+ CTEPrint("\tCommand: 0x") ; DbgPrintNum(pNCB->ncb_command) ;
+ CTEPrint(" NCB Address: 0x") ; DbgPrintNum( (ULONG) pNCB ) ;
+ }
+ goto SkipPost ;
+ }
+
+ //
+ // call the post-routine only if this was a no-wait call and if
+ // the post-routine has been specified!
+ //
+ if ( fAsync && pNCB->ncb_post )
+ {
+ typedef void (CALLBACK * VXDNCBPost )( void ) ;
+ VXDNCBPost ncbpost = (VXDNCBPost) pNCB->ncb_post ;
+
+ //
+ // Clients are expecting EBX to point to the NCB (instead of
+ // pushing it on the stack...). The post routine may trash
+ // ebp also, so save it.
+ //
+ _asm push ebp ;
+ _asm mov ebx, pNCB ;
+ ncbpost() ;
+ _asm pop ebp ;
+ }
+
+SkipPost:
+ //
+ // Now that we've completed the NCB, unblock if it was a Wait NCB
+ //
+ if ( !fAsync )
+ {
+ PBLOCKING_NCB_CONTEXT pBlkNcbContext;
+ PLIST_ENTRY pHead, pEntry ;
+
+ //
+ // find the blocking ncb context from the list corresponding to this ncb
+ //
+ pHead = &NbtConfig.BlockingNcbs;
+ pEntry = pHead->Flink;
+ while( pEntry != pHead )
+ {
+ pBlkNcbContext = CONTAINING_RECORD( pEntry, BLOCKING_NCB_CONTEXT, Linkage ) ;
+ if (pBlkNcbContext->pNCB == pNCB)
+ break;
+ else
+ pBlkNcbContext = NULL;
+ pEntry = pEntry->Flink;
+ }
+
+ if (pBlkNcbContext)
+ {
+ ASSERT(pBlkNcbContext->Verify == NBT_VERIFY_BLOCKING_NCB);
+
+ //
+ // if the ncb is blocked for completion, remove the context from
+ // the list first (important!) and then signal the thread that we
+ // are done. Then free the memory.
+ //
+ if ( pBlkNcbContext->fBlocked )
+ {
+ RemoveEntryList(&pBlkNcbContext->Linkage);
+ CTESignal( pBlkNcbContext->pWaitNCBBlock, 0 ) ;
+ CTEFreeMem(pBlkNcbContext->pWaitNCBBlock);
+ CTEFreeMem(pBlkNcbContext);
+ }
+ else
+ {
+ pBlkNcbContext->fNCBCompleted = TRUE;
+ }
+ }
+ else
+ {
+ DbgPrint("VxdIoComplete: didn't find blocking ncb context\r\n") ;
+ DbgPrint("for NCB Address: 0x") ; DbgPrintNum( (ULONG) pNCB ) ;
+ }
+ }
+}
+
+/*******************************************************************
+
+ NAME: VxdInitSessionSetup
+
+ SYNOPSIS: Common initialization required for Call and Listen
+
+ ENTRY: pDeviceContext - Adapter to setup on
+ pRequest - Request to fill in if successful
+ ppSessSetupContext - Context to be filled
+ pNCB - NCB doing the call/listen
+
+ EXIT:
+
+ RETURNS: NRC_GOODRET if successful, error code otherwise
+
+ NOTES:
+
+ HISTORY:
+ Johnl 26-May-1993 Created
+
+********************************************************************/
+
+NCBERR VxdInitSessionSetup( tDEVICECONTEXT * pDeviceContext,
+ TDI_REQUEST * pRequest,
+ PSESS_SETUP_CONTEXT * ppSessSetupContext,
+ NCB * pNCB )
+{
+ NTSTATUS status;
+ NCBERR errNCB ;
+ TDI_REQUEST_STATUS RequestStatus ;
+ tCLIENTELE * pClientEle ;
+ tCONNECTELE * pConnEle ;
+ tNAMEADDR * pNameAddr ;
+ USHORT NameType ;
+ BOOL fIsListen = ((pNCB->ncb_command & ~ASYNCH)
+ == NCBLISTEN) ;
+
+ *ppSessSetupContext = NULL ;
+
+ //
+ // Lookup the Client Element associated with this name and verify
+ // it's valid
+ //
+ if ( errNCB = VxdNameToClient( pDeviceContext,
+ pNCB->ncb_name,
+ NULL,
+ &pClientEle ))
+ {
+ return errNCB ;
+ }
+
+ if ( pClientEle->fDeregistered )
+ return NRC_NOWILD ;
+
+ //
+ // Request.Handle.ConnectionContext will contain Connection
+ // element after we open the connection
+ //
+ if ( status = NbtOpenConnection( pRequest,
+ NULL, //ConnectionContext, // Passed to connect and disconnect handlers
+ pDeviceContext ) )
+ {
+ return MapTDIStatus2NCBErr( status ) ;
+ }
+
+ //
+ // Initialize the connection context (used by Vxd disconnect handler)
+ //
+ pConnEle = (tCONNECTELE *) pRequest->Handle.ConnectionContext ;
+ pConnEle->ConnectContext = pConnEle ;
+
+ if ( status = NbtAssociateAddress( pRequest,
+ pClientEle,
+ NULL ))
+ {
+ goto ErrorExit1 ;
+ }
+
+ ASSERT( sizeof( SESS_SETUP_CONTEXT ) <= (sizeof( pNCB->ncb_reserve ) +
+ sizeof( pNCB->ncb_event )) ) ;
+ *ppSessSetupContext = (PSESS_SETUP_CONTEXT) pNCB->ncb_reserve ;
+ if ( status = AllocSessSetupContext( *ppSessSetupContext,
+ *pNCB->ncb_callname == '*' ) )
+ goto ErrorExit0 ;
+
+ //
+ // Listen for '*' uses a NULL Request remote address
+ //
+ if ( *pNCB->ncb_callname != '*' )
+ {
+ InitNBTDIConnectInfo( (*ppSessSetupContext)->pRequestConnect,
+ (*ppSessSetupContext)->pRequestConnect->RemoteAddress,
+ pNCB->ncb_callname ) ;
+ }
+
+ InitNBTDIConnectInfo( (*ppSessSetupContext)->pReturnConnect,
+ (*ppSessSetupContext)->pReturnConnect->RemoteAddress,
+ pNCB->ncb_name ) ;
+ (*ppSessSetupContext)->fIsWorldListen = (pNCB->ncb_callname[0] == '*') ;
+ (*ppSessSetupContext)->pConnEle = pConnEle ;
+
+ return NRC_GOODRET ;
+
+ErrorExit0:
+ if ( !(NbtDisassociateAddress( pRequest ) == TDI_SUCCESS))
+ CTEPrint("VxdInitSessionSetup: AllocSesssetupContext failed and DisassociateAddress failed\r\n") ;
+
+ErrorExit1:
+ REQUIRE( NbtCloseConnection( pRequest,
+ &RequestStatus,
+ pDeviceContext,
+ NULL ) == TDI_SUCCESS ) ;
+
+ return MapTDIStatus2NCBErr( status ) ;
+}
+
+/*******************************************************************
+
+ NAME: VxdFindClientElement
+
+ SYNOPSIS: Finds the appropriate client element
+
+ ENTRY: pDeviceContext - Device to search on
+ ncbnum - NCB Name Number
+ ppClientEle - Receives result of search
+ Type - If CLIENT_BC (broadcast), then the Broadcast client
+ element for the pDeviceContext adapter is returned
+
+ RETURNS: STATUS_SUCCESS if the name is found, error code otherwise
+
+ NOTES: The device context points to a list of Address elements (one
+ address element for each Netbios name in the system). Each
+ address element has a Client Element list hanging off of it.
+ We return the first client element off of the Address Element
+ as there shouldn't be more then one client (is this true?).
+
+ HISTORY:
+ Johnl 23-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdFindClientElement( tDEVICECONTEXT * pDeviceContext,
+ UCHAR ncbnum,
+ tCLIENTELE * * ppClientEle,
+ enum CLIENT_TYPE Type )
+{
+ ASSERT( pDeviceContext != NULL ) ;
+ if ( !pDeviceContext )
+ return NRC_SYSTEM ;
+
+ if ( Type != CLIENT_BC )
+ {
+ if ( ncbnum > pDeviceContext->cMaxNames || !pDeviceContext->pNameTable[ncbnum] )
+ return NRC_ILLNN ;
+
+ *ppClientEle = (tCLIENTELE *) pDeviceContext->pNameTable[ncbnum] ;
+ return NRC_GOODRET ;
+ }
+ else
+ {
+ NTSTATUS status;
+ tCLIENTELE * pClientEleBcast ;
+ UCHAR pName[NETBIOS_NAME_SIZE];
+ tNAMEADDR * pNameAddr;
+ PLIST_ENTRY pHead;
+ PLIST_ENTRY pEntry;
+
+ //
+ // find the * name in the local hash table
+ //
+ CTEZeroMemory(pName,NETBIOS_NAME_SIZE);
+
+ pName[0] = '*';
+ status = FindInHashTable(NbtConfig.pLocalHashTbl,
+ pName,
+ NbtConfig.pScope,
+ &pNameAddr);
+
+ if (NT_SUCCESS(status))
+ {
+ pHead = &pNameAddr->pAddressEle->ClientHead;
+ pEntry = pHead->Flink;
+
+ while ( pEntry != pHead )
+ {
+ pClientEleBcast = CONTAINING_RECORD( pEntry, tCLIENTELE, Linkage ) ;
+ if ( pClientEleBcast->pDeviceContext == pDeviceContext )
+ {
+ *ppClientEle = pClientEleBcast ;
+ break ;
+ }
+ pEntry = pEntry->Flink ;
+ }
+ }
+ else
+ {
+ return(NRC_ILLNN);
+ }
+
+ if ( pEntry == pHead )
+ return NRC_ILLNN ;
+ }
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdFindConnectElement
+
+ SYNOPSIS: Finds the appropriate connect element from the
+ session number
+
+ ENTRY: pDeviceContext - Device to search on
+ lsn - NCB LS Number
+ ppConnectEle - Receives result of search
+
+ RETURNS: NRC_GOODRET if successful, error otherwise
+
+ NOTES: LSN 0 will be disallowed because pSessionTable[0] is always
+ NULL
+
+ HISTORY:
+ Johnl 23-Apr-1993 Created
+
+********************************************************************/
+
+NCBERR VxdFindConnectElement( tDEVICECONTEXT * pDeviceContext,
+ NCB * pNCB,
+ tCONNECTELE * * ppConnectEle )
+{
+ UCHAR lsn ;
+ ASSERT( pNCB != NULL ) ;
+ ASSERT( pDeviceContext != NULL ) ;
+
+ if ( !pDeviceContext || !pNCB )
+ return NRC_SYSTEM ;
+
+ lsn = pNCB->ncb_lsn ;
+ if ( lsn > pDeviceContext->cMaxSessions || !pDeviceContext->pSessionTable[lsn] )
+ return NRC_SNUMOUT ;
+
+ *ppConnectEle = pDeviceContext->pSessionTable[lsn] ;
+
+ //
+ // Check to see if the connection is down but the NB client hasn't been
+ // notified, if so notify them and remove the session from the table
+ //
+ if ( ( (*ppConnectEle)->state == NBT_ASSOCIATED ||
+ (*ppConnectEle)->state == NBT_IDLE ) &&
+ (*ppConnectEle)->RefCount == 1 )
+ {
+ DbgPrint("VxdFindConnectElement: Deleting connection element\r\n") ;
+ NbtDereferenceConnection( *ppConnectEle ) ;
+ REQUIRE( NBUnregister( pDeviceContext, lsn, NB_SESSION )) ;
+ return NRC_SCLOSED ;
+ }
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: VxdFindLSN
+
+ SYNOPSIS: Finds a session number from its tCONNECTELE *.
+
+ ENTRY: pDeviceContext - Device to search on
+ pConnectEle - Connect element to find
+ plsn - Index pConnectEle was found at
+
+ NOTES:
+
+ HISTORY:
+ Johnl 07-Jul-1993 Created
+
+********************************************************************/
+
+NCBERR VxdFindLSN( tDEVICECONTEXT * pDeviceContext,
+ tCONNECTELE * pConnectEle,
+ UCHAR * plsn )
+{
+ ASSERT( (pDeviceContext != NULL) && (pConnectEle != NULL) && (plsn != NULL)) ;
+ ASSERT( pConnectEle->Verify == NBT_VERIFY_CONNECTION ||
+ pConnectEle->Verify == NBT_VERIFY_CONNECTION_DOWN ) ;
+
+ for ( *plsn = 0 ; *plsn <= pDeviceContext->cMaxSessions ; (*plsn)++ )
+ {
+ if ( pDeviceContext->pSessionTable[*plsn] == pConnectEle )
+ return NRC_GOODRET ;
+ }
+
+ ASSERT( FALSE ) ;
+ return NRC_SNUMOUT ;
+}
+
+/*******************************************************************
+
+ NAME: VxdFindNameNum
+
+ SYNOPSIS: Finds a name number from its tADDRESSELE *.
+
+ ENTRY: pDeviceContext - Device to search on
+ pAddressEle - Address element to find
+ pNum - Index pAddressEle was found at
+
+ NOTES:
+
+ HISTORY:
+ Johnl 07-Jul-1993 Created
+
+********************************************************************/
+
+NCBERR VxdFindNameNum( tDEVICECONTEXT * pDeviceContext,
+ tADDRESSELE * pAddressEle,
+ UCHAR * pNum )
+{
+ tCLIENTELE *pClientEle;
+
+ ASSERT( (pDeviceContext != NULL) && (pAddressEle != NULL) && (pNum != NULL)) ;
+ ASSERT( pAddressEle->Verify == NBT_VERIFY_ADDRESS ) ;
+
+ for ( *pNum = 0 ; *pNum <= pDeviceContext->cMaxNames ; (*pNum)++ )
+ {
+ pClientEle = pDeviceContext->pNameTable[*pNum];
+
+ if ( (pClientEle) && (pClientEle->pAddress == pAddressEle ) )
+ return NRC_GOODRET ;
+ }
+
+ return NRC_ILLNN ;
+}
+
+/*******************************************************************
+
+ NAME: VxdNameToClient
+
+ SYNOPSIS: Converts a ncb_callname to the corresponding client element
+ in the name table
+
+ ENTRY: pDeviceContext - Device to search on
+ pchName - Name to find
+ pNameNum - Index into table name number is at (Optional)
+ ppClientEle - Client element in the name table
+
+ NOTES:
+
+ HISTORY:
+ Johnl 15-Oct-1993 Created
+
+********************************************************************/
+
+NCBERR VxdNameToClient( tDEVICECONTEXT * pDeviceContext,
+ CHAR * pName,
+ UCHAR * pNameNum,
+ tCLIENTELE * * ppClientEle )
+{
+ USHORT NameType ;
+ tNAMEADDR * pNameAddr ;
+ UCHAR NameNum ;
+ NTSTATUS status;
+
+ //
+ // Lookup the Client Element associated with this name
+ //
+ if ( pName[0] == '*' )
+ {
+ return NRC_NOWILD ; // Also means name not found
+ }
+
+ status = FindInHashTable(
+ NbtConfig.pLocalHashTbl,
+ pName,
+ NbtConfig.pScope,
+ &pNameAddr);
+
+ if (!NT_SUCCESS(status))
+ {
+ return NRC_NOWILD ; // Also means name not found
+ }
+
+ //
+ // if the name is not registered on the adapter (provided by the client)
+ // tell the client so!
+ //
+ if ( pNameAddr->AdapterMask &&
+ !(pNameAddr->AdapterMask & pDeviceContext->AdapterNumber) )
+ {
+ DbgPrint("VxdNameToClient: wrong DeviceContext element\r\n") ;
+ return NRC_NOWILD ;
+ }
+
+ if ( VxdFindNameNum( pDeviceContext, pNameAddr->pAddressEle, &NameNum ))
+ {
+ ASSERT( FALSE ) ;
+ return NRC_NOWILD ;
+ }
+
+ REQUIRE( !VxdFindClientElement( pDeviceContext,
+ NameNum,
+ ppClientEle,
+ CLIENT_LOCAL )) ;
+ ASSERT( (*ppClientEle)->Verify == NBT_VERIFY_CLIENT ) ;
+
+ if ( pNameNum != NULL )
+ *pNameNum = NameNum ;
+
+ return NRC_GOODRET ;
+}
+
+/*******************************************************************
+
+ NAME: NBRegister
+
+ SYNOPSIS: Finds the next available slot in apElem and assigns
+ pElem to that slot according to Netbios rules
+
+
+ ENTRY: pDeviceContext - Adapter we are adding name to
+ pNCBNum - Receives the found free slot
+ pElem - Element we are registering
+ NbTable - Indicates the Name table or session table
+
+ EXIT: *pNCBNum will point to the found slot and
+ apElem[*pNCBNum] will point to pElem
+
+ RETURNS: TRUE if we found a free slot, FALSE if the table was
+ full.
+
+ NOTES: The Netbios spec states that returned NCB nums and Logical
+ Session numbers increase to 254 until they wrap to 1 (0
+ is reserved for the adapter name).
+
+ HISTORY:
+ Johnl 28-Apr-1993 Created
+
+********************************************************************/
+
+BOOL NBRegister( tDEVICECONTEXT * pDeviceContext,
+ UCHAR * pNCBNum,
+ PVOID pElem,
+ NB_TABLE_TYPE NbTable )
+{
+ UCHAR i ;
+ BOOL fFound = FALSE ;
+ BOOL fPassTwo = FALSE ;
+ UCHAR MaxNCBNum ;
+ UCHAR * piCurrent ;
+ PVOID * apElem ;
+
+ ASSERT( pElem != NULL ) ;
+
+ if ( NbTable == NB_NAME )
+ {
+ MaxNCBNum = pDeviceContext->cMaxNames ;
+ apElem = pDeviceContext->pNameTable ;
+ piCurrent = &pDeviceContext->iNcbNum ;
+ }
+ else
+ {
+ MaxNCBNum = pDeviceContext->cMaxSessions ;
+ apElem = pDeviceContext->pSessionTable ;
+ piCurrent = &pDeviceContext->iLSNum ;
+ }
+
+ //
+ // Find the next free name number and store it in pNCBNum
+ //
+ for ( i = *piCurrent ; ; i++ )
+ {
+ if ( i > MaxNCBNum )
+ i = 1 ;
+
+ if ( !apElem[i] )
+ {
+ fFound = TRUE ;
+ break ;
+ }
+
+ //
+ // Second time we hit *piCurrent means there are no free slots
+ //
+ if ( i == *piCurrent)
+ {
+ if ( fPassTwo )
+ break ;
+ else
+ fPassTwo = TRUE ;
+ }
+ }
+
+ if ( fFound )
+ {
+ apElem[i] = pElem ;
+ *pNCBNum = *piCurrent = i ;
+
+ (*piCurrent)++ ;
+ if ( *piCurrent > MaxNCBNum )
+ *piCurrent = 1 ;
+ }
+
+ return fFound ;
+}
+
+/*******************************************************************
+
+ NAME: NBUnregister
+
+ SYNOPSIS: Invalidates the passed netbios number
+
+ ENTRY: NCBNum - Name number to unregister
+
+ EXIT: The name number entry will be set to NULL
+
+
+ RETURNS: TRUE if we freed the slot, FALSE if the name wasn't
+ registered in the first place or it's out of range
+
+ NOTES:
+
+ HISTORY:
+ Johnl 05-May-1993 Created
+
+********************************************************************/
+
+BOOL NBUnregister( tDEVICECONTEXT * pDeviceContext,
+ UCHAR NCBNum,
+ NB_TABLE_TYPE NbTable )
+{
+ UCHAR MaxNCBNum ;
+ PVOID * apElem ;
+
+ if ( NbTable == NB_NAME )
+ {
+ MaxNCBNum = pDeviceContext->cMaxNames ;
+ apElem = pDeviceContext->pNameTable ;
+ }
+ else
+ {
+ MaxNCBNum = pDeviceContext->cMaxSessions ;
+ apElem = pDeviceContext->pSessionTable ;
+ }
+
+ if ( NCBNum > MaxNCBNum || apElem[NCBNum] == NULL )
+ {
+ return FALSE ;
+ }
+
+ apElem[NCBNum] = NULL ;
+
+ return TRUE ;
+}
+
+/*******************************************************************
+
+ NAME: VxdCompleteSessionNcbs
+
+ SYNOPSIS: Finds all NCBs attached to a session and completes them
+
+ ENTRY: pDeviceContext - Device we are on
+ pConnEle - Session connection element to complete NCBs on
+
+ NOTES:
+
+ HISTORY:
+ Johnl 16-Aug-1993 Broke out as common code
+
+********************************************************************/
+
+TDI_STATUS VxdCompleteSessionNcbs( tDEVICECONTEXT * pDeviceContext,
+ tCONNECTELE * pConnEle )
+{
+ PLIST_ENTRY pHead, pEntry ;
+ PRCV_CONTEXT prcvCont ;
+ BOOL fCompleteToClient = TRUE ;
+ UCHAR lsn ;
+ NCBERR errNCB ;
+ BOOL fAnyFound = FALSE ;
+
+ ASSERT( pConnEle != NULL ) ;
+ ASSERT( pConnEle->Verify == NBT_VERIFY_CONNECTION ||
+ pConnEle->Verify == NBT_VERIFY_CONNECTION_DOWN ) ;
+
+ if ( errNCB = VxdFindLSN( pDeviceContext,
+ pConnEle,
+ &lsn ))
+ {
+ //
+ // This shouldn't happen but watch for it in case we get in a
+ // weird situation
+ //
+ DbgPrint("VxdCompleteSessionNCBs - Warning: VxdFindLsn failed\r\n") ;
+ return STATUS_UNSUCCESSFUL ;
+ }
+
+ //
+ // Complete the first RcvAny
+ //
+ if ( pConnEle->pClientEle &&
+ !IsListEmpty( &pConnEle->pClientEle->RcvAnyHead ))
+ {
+ pEntry = RemoveHeadList( &pConnEle->pClientEle->RcvAnyHead ) ;
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ //
+ // Set the session number so the client knows which session is going
+ // away.
+ //
+ prcvCont->pNCB->ncb_lsn = lsn ;
+ CTEIoComplete( prcvCont->pNCB,
+ STATUS_CONNECTION_DISCONNECTED,
+ 0 ) ;
+ fAnyFound = TRUE ;
+ }
+
+ //
+ // Now kill all of the outstanding receives. Sends are completed as
+ // they are submitted so nothing to kill.
+ //
+ while ( !IsListEmpty( &pConnEle->RcvHead ))
+ {
+ pEntry = RemoveHeadList( &pConnEle->RcvHead ) ;
+ prcvCont = CONTAINING_RECORD( pEntry, RCV_CONTEXT, ListEntry ) ;
+ ASSERT( prcvCont->Signature == RCVCONT_SIGN ) ;
+
+ CTEIoComplete( prcvCont->pNCB,
+ STATUS_CONNECTION_DISCONNECTED,
+ 0 ) ;
+ fAnyFound = TRUE ;
+ }
+
+ //
+ // Once the client has been notified, deref the connection
+ // element so the memory will be deleted when the connection is
+ // closed. If the client wasn't notified, then the connection remains
+ // in our table until the next NCB on this session.
+ //
+ if ( fAnyFound &&
+ !(pConnEle->Flags & NB_CLIENT_NOTIFIED) )
+ {
+ DbgPrint("CompleteSessionNcbs - Marking connection as notified\r\n") ;
+ pConnEle->Flags |= NB_CLIENT_NOTIFIED ;
+ NbtDereferenceConnection( pConnEle ) ;
+ }
+
+
+ return TDI_SUCCESS ;
+}
+
+/*******************************************************************
+
+ NAME: VxdTearDownSession
+
+ SYNOPSIS: Closes a session and deletes its session context
+
+ ENTRY: pConnEle - Pointer to connection session element to close
+ pCont - Session context to delete (or NULL to ignore)
+ pSessSetupContext - Session context to delete if non-NULL
+ pNCB - NCB to complete after disconnect finishes
+
+ NOTES:
+
+ HISTORY:
+ Johnl 16-Aug-1993 Commonized
+
+********************************************************************/
+
+void VxdTearDownSession( tDEVICECONTEXT * pDeviceContext,
+ tCONNECTELE * pConnEle,
+ PSESS_SETUP_CONTEXT pSessSetupContext,
+ NCB * pNCB )
+{
+ TDI_STATUS tdistatus ;
+ TDI_REQUEST Request ;
+
+ if ( pConnEle != NULL )
+ {
+ ASSERT((pConnEle->Verify == NBT_VERIFY_CONNECTION) ||
+ (pConnEle->Verify == NBT_VERIFY_CONNECTION_DOWN)) ;
+
+ Request.Handle.ConnectionContext = pConnEle ;
+
+ tdistatus = NbtDisconnect( &Request, 0, TDI_DISCONNECT_ABORT, NULL, NULL, NULL ) ;
+ if ( tdistatus && tdistatus != TDI_PENDING )
+ {
+ DbgPrint("VxdTearDownSession - NbtDisconnect returned error " ) ;
+ DbgPrintNum( tdistatus ) ;
+ DbgPrint("\r\n") ;
+ }
+
+ tdistatus = NbtCloseConnection( &Request,
+ NULL,
+ pDeviceContext,
+ NULL ) ;
+ if ( tdistatus && tdistatus != TDI_PENDING )
+ {
+ DbgPrint("VxdTearDownSession - NbtCloseConnection returned error " ) ;
+ DbgPrintNum( tdistatus ) ;
+ DbgPrint("\r\n") ;
+ }
+ }
+
+ if ( pSessSetupContext )
+ FreeSessSetupContext( pSessSetupContext ) ;
+}
+/*******************************************************************
+
+ NAME: AllocSessSetupContext
+
+ SYNOPSIS: Allocates and initializes a listen context structure
+
+ ENTRY: pSessSetupContext - Pointer to structure
+ fListenOnStar - TRUE if the request remote address should
+ be left as NULL
+
+ NOTES:
+
+ HISTORY:
+ Johnl 19-May-1993 Created
+
+********************************************************************/
+
+TDI_STATUS AllocSessSetupContext( PSESS_SETUP_CONTEXT pSessSetupContext,
+ BOOL fListenOnStar )
+{
+ CTEZeroMemory( pSessSetupContext, sizeof( SESS_SETUP_CONTEXT ) ) ;
+
+ if ( !(pSessSetupContext->pRequestConnect =
+ CTEAllocMem( sizeof( TDI_CONNECTION_INFORMATION ))) ||
+ !(pSessSetupContext->pReturnConnect =
+ CTEAllocMem( sizeof( TDI_CONNECTION_INFORMATION))) )
+ {
+ goto ErrorExit1 ;
+ }
+
+ pSessSetupContext->pRequestConnect->RemoteAddress = NULL ;
+ pSessSetupContext->pReturnConnect->RemoteAddress = NULL ;
+
+ if ( !(pSessSetupContext->pReturnConnect->RemoteAddress =
+ CTEAllocMem( sizeof( TA_NETBIOS_ADDRESS ))) ||
+ (!fListenOnStar &&
+ !(pSessSetupContext->pRequestConnect->RemoteAddress =
+ CTEAllocMem( sizeof( TA_NETBIOS_ADDRESS )))) )
+ {
+ goto ErrorExit0 ;
+ }
+
+ return TDI_SUCCESS ;
+
+ErrorExit0:
+ if ( pSessSetupContext->pRequestConnect->RemoteAddress)
+ CTEFreeMem( pSessSetupContext->pRequestConnect->RemoteAddress ) ;
+
+ if ( pSessSetupContext->pReturnConnect->RemoteAddress)
+ CTEFreeMem( pSessSetupContext->pReturnConnect->RemoteAddress ) ;
+
+ErrorExit1:
+ if ( pSessSetupContext->pRequestConnect)
+ CTEFreeMem( pSessSetupContext->pRequestConnect ) ;
+
+ if ( pSessSetupContext->pReturnConnect)
+ CTEFreeMem( pSessSetupContext->pReturnConnect ) ;
+
+ return TDI_NO_RESOURCES ;
+}
+
+/*******************************************************************
+
+ NAME: FreeSessSetupContext
+
+ SYNOPSIS: Frees a successfully initialized listen context
+
+ ENTRY: pSessSetupContext - Context to be freed
+
+ HISTORY:
+ Johnl 19-May-1993 Created
+
+********************************************************************/
+
+void FreeSessSetupContext( PSESS_SETUP_CONTEXT pSessSetupContext )
+{
+ if ( pSessSetupContext->pRequestConnect->RemoteAddress )
+ CTEFreeMem( pSessSetupContext->pRequestConnect->RemoteAddress ) ;
+
+ CTEFreeMem( pSessSetupContext->pReturnConnect->RemoteAddress ) ;
+ CTEFreeMem( pSessSetupContext->pRequestConnect ) ;
+ CTEFreeMem( pSessSetupContext->pReturnConnect ) ;
+}
+
+
+/*******************************************************************
+
+ NAME: DelayedSessEstablish
+
+ SYNOPSIS: This routine is called by VxdScheduleDelayedEvent.
+ After name query is successful, we typically make a tcp
+ connection. We delay that step until later so that stack
+ usage is reduced. (yes, there is only 4k of stack on chicago!)
+
+ ENTRY: pContext - context that contains the actual parms
+
+ RETURNS: Nothing
+
+ HISTORY:
+ Koti Dec. 19, 94
+
+********************************************************************/
+VOID DelayedSessEstablish( PVOID pContext )
+{
+ tDGRAM_SEND_TRACKING *pTracker;
+ NTSTATUS status;
+ COMPLETIONCLIENT pClientCompletion;
+
+ //
+ // get our parameters out
+ //
+ pTracker = ((NBT_WORK_ITEM_CONTEXT *)pContext)->pTracker;
+ status = (NTSTATUS)((NBT_WORK_ITEM_CONTEXT *)pContext)->pClientContext;
+ pClientCompletion = ((NBT_WORK_ITEM_CONTEXT *)pContext)->ClientCompletion;
+
+ CTEMemFree(pContext);
+
+ CompleteClientReq(pClientCompletion,
+ pTracker,
+ status);
+}
+
+
+
+/*******************************************************************
+
+ NAME: VxdApiWorker
+
+ SYNOPSIS: When clients such as another vxd or a V86 app (such as
+ nbtstat.exe) make requests for information or some service,
+ this is the routine that gets called.
+
+ ENTRY: OpCode - what info or service is being requested
+ ClientBuffer - buffer in which to pass info
+ ClientBufLen - how big is the buffer
+
+ RETURNS: ErrorCode from the operation (0 if success)
+
+ HISTORY:
+ Koti 16-Jun-1994 Created
+
+********************************************************************/
+
+NTSTATUS
+VxdApiWorker(
+ DWORD Ioctl,
+ PVOID ClientOutBuffer,
+ DWORD ClientOutBufLen,
+ PVOID ClientInBuffer,
+ DWORD ClientInBufLen,
+ DWORD fOkToTrashInputBuffer
+ )
+{
+
+ NTSTATUS status;
+ USHORT OpCode;
+ int i;
+ USHORT NumLanas;
+ PCHAR pchBuffer;
+ DWORD dwSize;
+ DWORD dwBytesToCopy;
+ PULONG pIpAddr;
+ PLIST_ENTRY pEntry,pHead;
+ tDEVICECONTEXT *pDeviceContext;
+ NCB ncb;
+ UCHAR retcode;
+ tIPANDNAMEINFO *pIpAndNameInfo;
+ tIPCONFIG_INFO *pIpCfg;
+
+
+ status = STATUS_SUCCESS;
+
+ dwSize = ClientOutBufLen;
+
+ // always use the first adapter on the list
+ pDeviceContext = CONTAINING_RECORD(NbtConfig.DeviceContexts.Flink,tDEVICECONTEXT,Linkage);
+
+ OpCode = (USHORT)Ioctl;
+
+ switch (OpCode)
+ {
+ // nbtstat -<any option>
+ case IOCTL_NETBT_GET_IP_ADDRS :
+
+ if (ClientOutBufLen < sizeof(ULONG)*(NbtConfig.AdapterCount + 1))
+ {
+ return( STATUS_BUFFER_OVERFLOW );
+ }
+
+ if (!ClientOutBuffer)
+ {
+ return( STATUS_INVALID_PARAMETER );
+ }
+ pIpAddr = (PULONG )ClientOutBuffer;
+
+ pEntry = pHead = &NbtConfig.DeviceContexts;
+ while ((pEntry = pEntry->Flink) != pHead)
+ {
+ pDeviceContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
+ if (pDeviceContext->IpAddress)
+ {
+ *pIpAddr = pDeviceContext->IpAddress;
+ pIpAddr++;
+ }
+ }
+ //
+ // put a 0 address on the end
+ //
+ *pIpAddr = 0;
+
+ status = STATUS_SUCCESS;
+
+ break;
+
+ // nbtstat -n (or -N)
+ case IOCTL_NETBT_GET_LOCAL_NAMES :
+
+ // nbtstat -c
+ case IOCTL_NETBT_GET_REMOTE_NAMES :
+
+ if (!ClientOutBuffer || ClientOutBufLen == 0)
+ return (STATUS_INSUFFICIENT_RESOURCES);
+
+ if (OpCode == IOCTL_NETBT_GET_REMOTE_NAMES )
+ {
+ // make this null, so NbtQueryAda..() knows this is for remote
+ pDeviceContext = NULL;
+ }
+
+ // return an array of netbios names that are registered
+ status = NbtQueryAdapterStatus(pDeviceContext,
+ &pchBuffer,
+ &dwSize);
+ break;
+
+ // nbtstat -r
+ case IOCTL_NETBT_GET_BCAST_NAMES :
+
+ // return an array of netbios names that are registered
+ status = NbtQueryBcastVsWins(pDeviceContext,&pchBuffer,&dwSize);
+
+ break;
+
+ // nbtstat -R
+ case IOCTL_NETBT_PURGE_CACHE :
+
+ status = NbtResyncRemoteCache();
+ break;
+
+ // nbtstat -s, nbtstat -S
+ case IOCTL_NETBT_GET_CONNECTIONS :
+
+ // return an array of netbios names that are registered
+ status = NbtQueryConnectionList(NULL,
+ &pchBuffer,
+ &dwSize);
+ break;
+
+ // nbtstat -a, nbtstat -A
+ case IOCTL_NETBT_ADAPTER_STATUS:
+
+ if (!ClientOutBuffer)
+ {
+ return( STATUS_INVALID_PARAMETER );
+ }
+
+ CTEZeroMemory( &ncb, sizeof(NCB) );
+
+ ncb.ncb_command = NCBASTAT;
+ ncb.ncb_buffer = ClientOutBuffer;
+ ncb.ncb_length = ClientOutBufLen;
+ ncb.ncb_lana_num = pDeviceContext->iLana;
+
+ if (!ClientInBuffer)
+ {
+ return( STATUS_INVALID_PARAMETER );
+ }
+ pIpAndNameInfo = (tIPANDNAMEINFO *)ClientInBuffer;
+
+ //
+ // see if Ipaddress is specified: if yes, use it
+ //
+ if ( pIpAndNameInfo->IpAddress )
+ {
+ ncb.ncb_callname[0] = '*';
+ retcode = VNBT_NCB_X( &ncb, 0, &pIpAndNameInfo->IpAddress, 0, 0 );
+ }
+ //
+ // no ipaddress: use the name that's given to us
+ //
+ else
+ {
+ CTEMemCopy(
+ &ncb.ncb_callname[0],
+ &(pIpAndNameInfo->NetbiosAddress.Address[0].Address[0].NetbiosName[0]),
+ NCBNAMSZ );
+ retcode = VNBT_NCB_X( &ncb, 0, 0, 0, 0 );
+ }
+
+ status = STATUS_UNSUCCESSFUL;
+ if (!retcode)
+ {
+ if (ncb.ncb_retcode == NRC_GOODRET)
+ status = STATUS_SUCCESS;
+ else if (ncb.ncb_retcode == NRC_INCOMP)
+ status = TDI_BUFFER_OVERFLOW;
+ }
+
+ break;
+
+ // ipconfig queries us for nodetype and scope
+ case IOCTL_NETBT_IPCONFIG_INFO:
+
+ dwBytesToCopy = sizeof(tIPCONFIG_INFO) +
+ NbtConfig.ScopeLength;
+
+ if ( !ClientOutBuffer || ClientOutBufLen < dwBytesToCopy )
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ pIpCfg = (tIPCONFIG_INFO *)ClientOutBuffer;
+
+ NumLanas = 0;
+ for ( i = 0; i < NBT_MAX_LANAS; i++)
+ {
+ if (LanaTable[i].pDeviceContext != NULL)
+ {
+ pDeviceContext = LanaTable[i].pDeviceContext;
+ pIpCfg->LanaInfo[NumLanas].LanaNumber = pDeviceContext->iLana;
+ pIpCfg->LanaInfo[NumLanas].IpAddress = pDeviceContext->IpAddress;
+ pIpCfg->LanaInfo[NumLanas].NameServerAddress = pDeviceContext->lNameServerAddress;
+ pIpCfg->LanaInfo[NumLanas].BackupServer = pDeviceContext->lBackupServer;
+ pIpCfg->LanaInfo[NumLanas].lDnsServerAddress = pDeviceContext->lDnsServerAddress;
+ pIpCfg->LanaInfo[NumLanas].lDnsBackupServer = pDeviceContext->lDnsBackupServer;
+ NumLanas++;
+ }
+ }
+
+ pIpCfg->NumLanas = NumLanas;
+
+ pIpCfg->NodeType = NodeType;
+
+ pIpCfg->ScopeLength = NbtConfig.ScopeLength;
+
+ CTEMemCopy( &pIpCfg->szScope[0],
+ NbtConfig.pScope,
+ NbtConfig.ScopeLength );
+
+ status = STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ //
+ // Copy the output into user's buffer
+ //
+ if ( (OpCode == IOCTL_NETBT_GET_LOCAL_NAMES) ||
+ (OpCode == IOCTL_NETBT_GET_REMOTE_NAMES) ||
+ (OpCode == IOCTL_NETBT_GET_CONNECTIONS) ||
+ (OpCode == IOCTL_NETBT_GET_BCAST_NAMES) )
+ {
+ if ( NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
+ {
+ if ( status == STATUS_BUFFER_OVERFLOW )
+ {
+ dwBytesToCopy = ClientOutBufLen;
+ }
+ else
+ {
+ dwBytesToCopy = dwSize;
+ status = STATUS_SUCCESS;
+ }
+ CTEMemCopy( ClientOutBuffer, pchBuffer, dwBytesToCopy ) ;
+
+ CTEMemFree((PVOID)pchBuffer);
+ }
+ }
+
+ //
+ // we may be called either through the vxd entry point which 16 bit apps
+ // will do (for now, only nbtstat.exe), or through the file system api's
+ // which 32 bit apps will do via CreateFile and ioctl.
+ // If we came here through file system (i.e.VNBT_DeviceIoControl called us)
+ // then don't trash the input buffer since the status gets passed back as
+ // it is. For 16 bit apps (i.e.VNBT_Api_Handler called us), the only way
+ // we can pass status back (without major changes all over) is through the
+ // input buffer.
+ //
+ if ( ClientInBuffer && fOkToTrashInputBuffer )
+ {
+ *(NTSTATUS *)ClientInBuffer = status;
+ }
+
+ return( status );
+}
+
+/*******************************************************************
+
+ NAME: PostInit_Proc
+
+ SYNOPSIS: After the whole system is initialized, we get the
+ Sys_Vm_Init message and that's when this routine gets called.
+ This can be used for any post-processing, but for now we
+ only use it to load lmhosts (this way, we can load all the
+ #INCLUDE files which have UNC's in them, since now we know
+ the net is up).
+
+ RETURNS: ErrorCode from the operation (0 if success)
+
+ HISTORY:
+ Koti 12-Jul-1994 Created
+
+********************************************************************/
+
+NTSTATUS
+PostInit_Proc()
+{
+
+ LONG lRetcode;
+
+ CachePrimed = FALSE;
+
+ CTEPagedCode();
+
+
+ lRetcode = PrimeCache( NbtConfig.pLmHosts,
+ NULL,
+ TRUE,
+ NULL) ;
+ if (lRetcode != -1)
+ {
+ CachePrimed = TRUE ;
+ }
+
+}
+
+
+/*******************************************************************
+
+ NAME: CTEAllocInitMem
+
+ SYNOPSIS: Allocates memory during driver initialization
+
+ NOTES: If first allocation fails, we refill the heap spare and
+ try again. We can only do this during driver initialization
+ because the act of refilling may yield the current
+ thread.
+
+ HISTORY:
+ Johnl 27-Aug-1993 Created
+********************************************************************/
+
+PVOID CTEAllocInitMem( ULONG cbBuff )
+{
+ PVOID pv = CTEAllocMem( cbBuff ) ;
+
+ if ( pv )
+ {
+ return pv ;
+ }
+ else if ( fInInit )
+ {
+ DbgPrint("CTEAllocInitMem: Failed allocation, trying again\r\n") ;
+ CTERefillMem() ;
+ pv = CTEAllocMem( cbBuff ) ;
+ }
+
+ return pv ;
+}
diff --git a/private/ntos/nbt/vxd/vxdstub.asm b/private/ntos/nbt/vxd/vxdstub.asm
new file mode 100644
index 000000000..0404c3dda
--- /dev/null
+++ b/private/ntos/nbt/vxd/vxdstub.asm
@@ -0,0 +1,250 @@
+ name vxdstub
+;************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1990-1991
+;
+; Title: VXDSTUB.ASM
+;
+; Date: 1-Jun-1991
+;
+; Author: Neil Sandlin
+;
+;************************************************************************
+ INCLUDE INT2FAPI.INC
+;----------------------------- M A C R O S ------------------------------
+Writel MACRO addr
+ push ax
+ push bx
+ push cx
+ push dx
+
+ mov dx,offset &addr ;Print
+ mov cx,&addr&l
+ mov bx,1 ;stdout
+ mov ah,40h ;write
+ int 21h
+
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ENDM
+
+;----------------------------- E Q U A T E S -----------------------------
+
+cr equ 0dh
+lf equ 0ah
+
+
+_TEXT segment word public 'CODE'
+ assume cs:_TEXT,ds:_DATA
+
+;*----------------------- TSR Data Area ---------------------*
+InstData Win386_Startup_Info_Struc <>
+oldint dd 0
+
+;*----------------------- TSR Code --------------------------*
+
+
+handle2f proc
+ cmp ax,1605h
+ jnz @f
+ push di
+ lea di,InstData
+ mov word ptr cs:[di].SIS_Next_Ptr,bx
+ mov word ptr cs:[di][2].SIS_Next_Ptr,es
+ pop di
+ push cs
+ pop es
+ lea bx,InstData
+@@:
+ jmp DWORD PTR [oldint]
+handle2f endp
+
+ ALIGN 16
+init_fence:
+
+_TEXT ends
+
+;*---------------------- Initialization Data ------------------------*
+
+_DATA segment word public 'DATA'
+
+TSR_rsv dw ?
+
+intmsg db cr,lf,'Hooking interrupt '
+intmsgx dd ?
+ db cr,lf
+intmsgl equ $-intmsg
+
+hndmsg db cr,lf,'ISR entry point: '
+hndmsga dd ?
+ db ':'
+hndmsgb dd ?
+ db ', length='
+hndmsgc dd ?
+ db 'h bytes'
+ db cr,lf
+hndmsgl equ $-hndmsg
+
+tsrmsg db 'TSR; reserving '
+tsrmsgx dd ?
+ db ' paragraphs'
+ db cr,lf
+tsrmsgl equ $-tsrmsg
+
+_DATA ends
+
+
+_TEXT segment word public 'CODE'
+;*-------------------------- Initialization Code ----------------------*
+
+vxdstub proc far
+ mov ax, _DATA
+ mov ds, ax
+
+; get a pointer to the name of the load file in the environment seg.
+
+ mov ah,62h
+ int 21h ;bx -> psp
+ mov es,bx
+ mov bx,2ch ;environment segment
+ mov es,es:[bx]
+ xor di,di
+ mov cx,-1 ;big number
+ xor al,al ;search for a null
+ cld
+@@:
+ repne scasb ;get past one null and stop
+ cmp byte ptr es:[di],0 ;another null
+ jnz @b ;no.
+ add di,3 ;skip the word before the name.
+
+; prepare part of the instance data list. Stuff in pointer to the file name
+; and refernce data
+
+ lea si,InstData
+ mov word ptr CS:[si].SIS_Version,3
+ mov word ptr CS:[si].SIS_Virt_Dev_File_Ptr,di
+ mov word ptr CS:[si][2].SIS_Virt_Dev_File_Ptr,es
+
+ mov word ptr cs:[si].SIS_Instance_Data_Ptr,0
+ mov word ptr cs:[si][2].SIS_Instance_Data_Ptr,0
+
+; Write message and hook interrupt 2f
+ mov ax, 2fh
+ mov bx, offset intmsgx
+ call hexasc
+
+ Writel intmsg
+
+ mov ah, 35h
+ mov al, 2fh
+ int 21h ; get old vector
+ mov WORD PTR cs:oldint,bx ; save old vector here
+ mov WORD PTR cs:oldint+2,es
+
+ push ds
+ mov dx, offset handle2f
+ push cs ; get current code segment
+ pop ds
+ mov ah, 25h
+ mov al, 2fh ; vector to hook
+ int 21h ; hook that vector
+ pop ds
+
+
+; Print out some information about the handler
+
+ push cs ; code segment
+ pop ax
+ mov bx, offset hndmsga
+ call hexasc
+
+ mov ax, offset handle2f ; offset of ISR
+ mov bx, offset hndmsgb
+ call hexasc
+
+ mov ax, offset init_fence ; length in bytes of handler
+ mov bx, offset hndmsgc
+ call hexasc
+
+ Writel hndmsg
+
+; Compute size of TSR area
+
+ mov dx, offset init_fence ; start of initialization code
+ add dx, 15 ; round it off to paragraph
+ shr dx, 1 ; divide by 16
+ shr dx, 1
+ shr dx, 1
+ shr dx, 1
+ add dx, 32 ; add in PSP
+ mov TSR_rsv, dx ; save it
+
+ mov ax, dx
+ mov bx, offset tsrmsgx
+ call hexasc
+
+ Writel tsrmsg
+
+; Terminate and stay resident
+
+ mov ax, 3100h ; TSR
+ mov dx, TSR_rsv ; # of paragraphs to reserve
+ int 21h ; TSR
+vxdstub endp
+
+
+
+;************************************************************************
+;
+; HEXASC
+;
+; This subroutine formats hex values into ASCII
+; (utility routine from Advanced MS-DOS Programming)
+;
+;
+;************************************************************************
+
+hexasc proc near ; converts word to hex ASCII
+ ; call with AX = value,
+ ; DS:BX = address for string
+ ; returns AX, BX destroyed
+
+ push cx ; save registers
+ push dx
+
+ mov dx,4 ; initialize character counter
+hexasc1:
+ mov cx,4 ; isolate next four bits
+ rol ax,cl
+ mov cx,ax
+ and cx,0fh
+ add cx,'0' ; convert to ASCII
+ cmp cx,'9' ; is it 0-9?
+ jbe hexasc2 ; yes, jump
+ add cx,'A'-'9'-1 ; add fudge factor for A-F
+
+hexasc2: ; store this character
+ mov [bx],cl
+ inc bx ; bump string pointer
+
+ dec dx ; count characters converted
+ jnz hexasc1 ; loop, not four yet
+
+ pop dx ; restore registers
+ pop cx
+ ret ; back to caller
+
+hexasc endp
+
+
+
+_TEXT ends
+
+
+
+ end vxdstub
+
+ \ No newline at end of file
diff --git a/private/ntos/nbt/vxd/wfw.c b/private/ntos/nbt/vxd/wfw.c
new file mode 100644
index 000000000..c7f9bb7ce
--- /dev/null
+++ b/private/ntos/nbt/vxd/wfw.c
@@ -0,0 +1,694 @@
+/**********************************************************************/
+/** Microsoft Windows **/
+/** Copyright(c) Microsoft Corp., 1994 **/
+/**********************************************************************/
+
+/*
+
+ wfw.c
+
+ Contains VxD code that is specific to WFW
+
+
+ FILE HISTORY:
+ Johnl 14-Mar-1994 Created
+
+*/
+
+#include <nbtprocs.h>
+#include <tdiinfo.h>
+#include <llinfo.h>
+#include <ipinfo.h>
+#include <dhcpinfo.h>
+#include <nbtinfo.h>
+
+//
+// any digit 0 to 9 and '.' are legal characters in an ipaddr
+//
+#define IS_IPADDR_CHAR( ch ) ( (ch >= '0' && ch <= '9') || (ch == '.') )
+
+#define MAX_ADAPTER_DESCRIPTION_LENGTH 128
+
+#ifndef CHICAGO
+#pragma BEGIN_INIT
+
+extern char NBTSectionName[]; // Section in system.ini parameters are stored
+extern char DNSSectionName[]; // Section where we find DNS server ipaddrs
+
+void GetDnsServerAddress( ULONG IpAddr, PULONG pIpNameServer);
+
+extern ULONG CurrentIP ;
+
+/*******************************************************************
+
+ NAME: GetActiveLanasFromIP
+
+ SYNOPSIS: Queries TDI for all IP drivers that have a non-zero IP
+ address. For non-zero IP address, a DEVICE_CONTEXT is
+ created.
+
+ RETURNS: TRUE if successful, FALSE otherwise
+
+ NOTES: Even if we fail to setup a particular adapter, the Lana
+ count is maintained.
+
+ This routine is only used by Snowball
+
+********************************************************************/
+
+BOOL GetActiveLanasFromIP( VOID )
+{
+ NTSTATUS status ;
+ TDI_STATUS tdistatus ;
+ int i, j, k ;
+ uchar Context[CONTEXT_SIZE] ;
+ TDIObjectID ID ;
+ TDIEntityID EList[MAX_TDI_ENTITIES] ;
+ ULONG Size ;
+ UINT NumReturned ;
+ NDIS_BUFFER ndisbuff ;
+ BOOL fAnyValidIPs = FALSE ;
+ UINT iLanaOffset = 0 ;
+ IFEntry *ifeAdapterInfo[MAX_TDI_ENTITIES];
+ UINT AdptNum;
+ UCHAR MacAddr[6];
+ UCHAR PreviousNodeType;
+
+ //
+ // The first thing to do is get the list of available entities, and make
+ // sure that there are some interface entities present.
+ //
+ ID.toi_entity.tei_entity = GENERIC_ENTITY;
+ ID.toi_entity.tei_instance = 0;
+ ID.toi_class = INFO_CLASS_GENERIC;
+ ID.toi_type = INFO_TYPE_PROVIDER;
+ ID.toi_id = ENTITY_LIST_ID;
+
+ Size = sizeof(EList);
+ InitNDISBuff( &ndisbuff, &EList, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+
+ if (tdistatus != TDI_SUCCESS)
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetActiveLanasFromIP: Querying entity list failed\r\n")) ;
+ return FALSE ;
+ }
+
+ NumReturned = (uint)Size/sizeof(TDIEntityID);
+
+ AdptNum = 0;
+ //
+ // first find out info about the adapters
+ //
+ for (i = 0; i < NumReturned; i++)
+ {
+ //
+ // if this entity/instance describes an adapter
+ //
+ if ( EList[i].tei_entity == IF_ENTITY )
+ {
+ DWORD isMib;
+
+
+ ID.toi_entity.tei_entity = EList[i].tei_entity ;
+ ID.toi_entity.tei_instance = EList[i].tei_instance;
+ ID.toi_class = INFO_CLASS_GENERIC ;
+ ID.toi_type = INFO_TYPE_PROVIDER;
+ ID.toi_id = ENTITY_TYPE_ID ;
+
+ Size = sizeof( isMib );
+ InitNDISBuff( &ndisbuff, &isMib, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetActiveLanasFromIP: Getting isMib failed\r\n")) ;
+ return FALSE ;
+ }
+
+ //
+ // Does this entity support MIB
+ //
+ if (isMib != IF_MIB)
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetActiveLanasFromIP: skipping non-MIB entity\r\n")) ;
+ continue;
+ }
+
+ //
+ // MIB requests supported - query the adapter info
+ //
+
+ Size = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1;
+
+ ifeAdapterInfo[AdptNum] = (IFEntry *)CTEAllocInitMem((USHORT)Size);
+
+ if ( ifeAdapterInfo[AdptNum] == NULL )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetActiveLanasFromIP: Couldn't allocate AdapterInfo buffer\r\n")) ;
+ return FALSE;
+ }
+
+ ID.toi_class = INFO_CLASS_PROTOCOL;;
+ ID.toi_id = IF_MIB_STATS_ID;
+
+ Size = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1;
+ InitNDISBuff( &ndisbuff, ifeAdapterInfo[AdptNum], Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetActiveLanasFromIP: Getting IF type failed\r\n")) ;
+ for ( k=0; k<AdptNum; k++ )
+ {
+ CTEFreeMem( ifeAdapterInfo[k] ) ;
+ }
+ return FALSE ;
+ }
+
+ AdptNum++;
+ }
+ }
+
+ //
+ // now that we know about the adapters, get the ipaddrs
+ //
+ for (i = 0; i < NumReturned; i++)
+ {
+ if ( EList[i].tei_entity == CL_NL_ENTITY )
+ {
+ IPSNMPInfo IPStats ;
+ IPAddrEntry * pIAE ;
+ ULONG NLType ;
+ ULONG IpNameServer[COUNT_NS_ADDR];
+ ULONG IpDnsServer[COUNT_NS_ADDR];
+ UCHAR IpIndex;
+
+ //
+ // Does this entity support IP?
+ //
+
+ ID.toi_entity.tei_entity = EList[i].tei_entity ;
+ ID.toi_entity.tei_instance = EList[i].tei_instance;
+ ID.toi_class = INFO_CLASS_GENERIC ;
+ ID.toi_type = INFO_TYPE_PROVIDER;
+ ID.toi_id = ENTITY_TYPE_ID ;
+
+ Size = sizeof( NLType );
+ InitNDISBuff( &ndisbuff, &NLType, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetActiveLanasFromIP: Getting NL type failed\r\n")) ;
+ for ( k=0; k<AdptNum; k++ )
+ {
+ CTEFreeMem( ifeAdapterInfo[k] ) ;
+ }
+ return FALSE ;
+ }
+
+ if ( NLType != CL_NL_IP )
+ continue ;
+
+ //
+ // We've got an IP driver so get it's address table
+ //
+
+ ID.toi_class = INFO_CLASS_PROTOCOL ;
+ ID.toi_id = IP_MIB_STATS_ID;
+ Size = sizeof(IPStats);
+ InitNDISBuff( &ndisbuff, &IPStats, Size, NULL ) ;
+ memset(Context, 0, CONTEXT_SIZE);
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetActiveLanasFromIP: Getting IPStats failed\r\n")) ;
+ continue ;
+ }
+
+ if ( IPStats.ipsi_numaddr < 1 )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetActiveLanasFromIP: No IP Addresses installed\r\n")) ;
+ continue ;
+ }
+
+ Size = sizeof(IPAddrEntry) * IPStats.ipsi_numaddr ;
+ if ( !(pIAE = (IPAddrEntry*) CTEAllocInitMem( Size )) )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetActiveLanasFromIP: Couldn't allocate IP table buffer\r\n")) ;
+ continue ;
+ }
+
+ ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID ;
+ InitNDISBuff( &ndisbuff, pIAE, Size, NULL ) ;
+ memset( Context, 0, CONTEXT_SIZE ) ;
+ tdistatus = TdiVxdQueryInformationEx( 0,
+ &ID,
+ &ndisbuff,
+ &Size,
+ Context);
+ if ( tdistatus != TDI_SUCCESS )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "GetActiveLanasFromIP: Getting IP address table failed\r\n")) ;
+ CTEFreeMem( pIAE ) ;
+ continue ;
+ }
+
+ ASSERT( Size/sizeof(IPAddrEntry) >= IPStats.ipsi_numaddr ) ;
+
+ //
+ // We have the IP address table for this IP driver. Look for
+ // non-zero IP addresses
+ //
+
+ for ( j = 0 ; j < IPStats.ipsi_numaddr ; j++ )
+ {
+ //
+ // Skip the loopback address
+ //
+ if ((pIAE[j].iae_addr & 0x000000ff) == 0x0000007f )
+ {
+ continue ;
+ }
+
+ CurrentIP = pIAE[j].iae_addr ;
+ if (!CurrentIP)
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "Init: ipaddr is 0, but accepting\n\r")) ;
+ }
+
+ //
+ // now find out the mac address for this ipaddr
+ //
+ memset( MacAddr, 0, 6 ) ;
+ IpIndex = -1;
+ for ( k=0; k<AdptNum; k++ )
+ {
+ if ( ifeAdapterInfo[k]->if_index == pIAE[j].iae_index )
+ {
+ CTEMemCopy( MacAddr, ifeAdapterInfo[k]->if_physaddr, 6 );
+ IpIndex = ifeAdapterInfo[k]->if_index;
+ break;
+ }
+ }
+ ASSERT(IpIndex != -1);
+
+ PreviousNodeType = NodeType;
+
+ //
+ // This will re-read the DHCPable parameters now that we have
+ // a potential DHCP source
+ //
+ ReadParameters2( pNbtGlobConfig, NULL );
+
+ if (PreviousNodeType & PROXY)
+ {
+ NodeType |= PROXY;
+ }
+
+ //
+ // Get all the NBNS servers' and DNS servers' ipaddresses
+ //
+ GetNameServerAddress( CurrentIP, IpNameServer);
+
+ GetDnsServerAddress( CurrentIP, IpDnsServer);
+
+ //
+ // IP stores the address in network order, so we will un-network order
+ // them because that's what NBT expects (would be nice to avoid conversion)
+ //
+ status = CreateDeviceObject( pNbtGlobConfig,
+ htonl( pIAE[j].iae_addr ),
+ htonl( pIAE[j].iae_mask ),
+ IpNameServer[0],
+ IpNameServer[1],
+ IpDnsServer[0],
+ IpDnsServer[1],
+ MacAddr,
+ IpIndex
+ ) ;
+
+ if ( !NT_SUCCESS( status ) )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "Init: CreateDeviceObject failed\n\r")) ;
+ iLanaOffset++ ;
+ continue ;
+ }
+
+ if ( !RegisterLana( LanaBase + iLanaOffset ) )
+ {
+ CDbgPrint( DBGFLAG_ERROR, ( "Init: RegisterLana failed\n\r")) ;
+ iLanaOffset++ ;
+ continue ;
+ }
+
+ LanaTable[iLanaOffset].pDeviceContext =
+ (tDEVICECONTEXT*)pNbtGlobConfig->DeviceContexts.Blink ;
+ LanaTable[iLanaOffset].pDeviceContext->iLana = LanaBase +
+ iLanaOffset;
+ iLanaOffset++;
+ fAnyValidIPs = TRUE ;
+
+ } // addr traversal
+
+ CTEFreeMem( pIAE ) ;
+
+ } // if IP
+ } // entity traversal
+
+ for ( k=0; k<AdptNum; k++ )
+ {
+ CTEFreeMem( ifeAdapterInfo[k] ) ;
+ }
+
+ return fAnyValidIPs ;
+}
+
+/*******************************************************************
+
+ NAME: VxdReadIniString
+
+ SYNOPSIS: Vxd stub for CTEReadIniString
+
+ ENTRY: pchKey - Key value to look for in the NBT section
+ ppchString - Pointer to buffer found string is returned in
+
+ EXIT: ppchString will point to an allocated buffer
+
+ RETURNS: STATUS_SUCCESS if found
+
+ NOTES: The client must free ppchString when done with it
+
+ HISTORY:
+ Johnl 30-Aug-1993 Created
+ Koti 30-May-194 Added 3rd parm to GetProfileString
+
+********************************************************************/
+
+CHAR * GetProfileString( LPTSTR pchKey, LPTSTR * pchDefault, PCHAR SectName ) ;
+
+NTSTATUS VxdReadIniString( LPSTR pchKey, LPSTR * ppchString )
+{
+ char * pchTmp ;
+
+ if ( pchTmp = GetProfileString( pchKey, NULL, NBTSectionName ) )
+ {
+ if ( *ppchString = CTEAllocInitMem( strlen( pchTmp ) + 1) )
+ {
+ strcpy( *ppchString, pchTmp ) ;
+ return STATUS_SUCCESS ;
+ }
+ else
+ return STATUS_INSUFFICIENT_RESOURCES ;
+ }
+ else
+ {
+ //
+ // Does DHCP have it?
+ //
+
+ if ( pchTmp = (char *) GetDhcpOption( pchKey, 0 ) )
+ {
+ *ppchString = pchTmp ;
+ return STATUS_SUCCESS ;
+ }
+ }
+
+ return STATUS_UNSUCCESSFUL ;
+}
+
+
+/*******************************************************************
+
+ NAME: GetDnsServerAddress
+
+ SYNOPSIS: Gets the DNS server ipaddrs from the DNS section of system.ini
+
+ Or, if DHCP is installed and the DNS server addresses aren't
+ found, we get them from DHCP
+
+ ENTRY: IpAddr - If we can get from DHCP, get form this address
+ pIpDnsServer - Receives addresses if found (otherwise 0)
+
+ NOTES: This routine is only used by Snowball
+
+ HISTORY:
+ Koti 30-May-1994 Created
+
+********************************************************************/
+
+void GetDnsServerAddress( ULONG IpAddr, PULONG pIpDnsServer)
+{
+ UCHAR i ;
+ PUCHAR pchDnsSrv = "DNSServers" ;
+ UINT OptId;
+ PUCHAR pchTmp;
+ PUCHAR pchCurrent, pchNext;
+ LPTSTR pchString=NULL ;
+ TDI_STATUS tdistatus ;
+ BOOL fPrimaryFound = FALSE;
+ BOOL fOneMore=TRUE;
+ ULONG Buff[COUNT_NS_ADDR] ;
+
+
+
+ //
+ // initialize all of them to worst case
+ //
+ for ( i = 0; i < COUNT_NS_ADDR; i++)
+ {
+ pIpDnsServer[i] = LOOP_BACK ;
+ }
+
+ pchTmp = GetProfileString( pchDnsSrv, NULL, DNSSectionName );
+ if ( pchTmp == NULL )
+ {
+ goto Not_In_Sysini;
+ }
+
+ if ( !(pchString = CTEAllocInitMem( strlen( pchTmp ) + 1)) )
+ {
+ DbgPrint("GetDnsServerAddress: CTEAllocInitMem failed!\r\n") ;
+ goto Not_In_Sysini;
+ }
+
+ strcpy( pchString, pchTmp ) ;
+
+ //
+ // we are generating (upto) COUNT_NS_ADDR pointers each pointing to
+ // one ipaddr. The string in system.ini looks like:
+ // DNSServers = 11.101.4.26,200.200.200.200,1.2.3.4,1.91.245.10
+ //
+ pchNext = pchCurrent = pchString;
+
+ if ( IS_IPADDR_CHAR(*pchCurrent) ) // make sure at least one ipaddr defnd
+ {
+ i = 0;
+ while( (i < COUNT_NS_ADDR) && fOneMore )
+ {
+ while( IS_IPADDR_CHAR(*pchNext) )
+ pchNext++;
+
+ if ( *pchNext == ',' ) // ',' is the separator between 2 addrs
+ {
+ *pchNext = '\0';
+ pchNext++;
+ }
+ else
+ {
+ fOneMore = FALSE; // reached end of line
+ }
+
+ //
+ // as long as at least the first one ipaddr gets converted properly,
+ // ignore errors in others
+ //
+ if ( ConvertDottedDecimalToUlong( pchCurrent, &pIpDnsServer[i] ))
+ {
+ if ( i == 0 )
+ goto Not_In_Sysini;
+ else
+ pIpDnsServer[i] = LOOP_BACK ;
+ }
+
+ fPrimaryFound = TRUE; // => at least one ipaddr is good
+
+ i++;
+
+ pchCurrent = pchNext; // go, convert the next one
+ }
+ }
+
+
+Not_In_Sysini:
+
+ if( pchString != NULL )
+ {
+ CTEFreeMem( pchString ) ;
+ }
+
+ //
+ // if we didn't find in the .ini file, try getting them from DHCP
+ //
+ if ( !fPrimaryFound )
+ {
+ ULONG Size = sizeof( Buff ) ;
+
+ OptId = 6; // DNS Option
+
+ tdistatus = DhcpQueryOption( IpAddr,
+ OptId,
+ &Buff,
+ &Size ) ;
+
+ switch ( tdistatus )
+ {
+ case TDI_SUCCESS:
+ case TDI_BUFFER_OVERFLOW: // May be more then one our buffer will hold
+ for ( i = 0; i < COUNT_NS_ADDR; i++ )
+ {
+ if ( Size >= (sizeof(ULONG)*(i+1)))
+ pIpDnsServer[i] = htonl(Buff[i]) ;
+ }
+ break ;
+
+ case TDI_INVALID_PARAMETER: // Option not found
+ break ;
+
+ default:
+ ASSERT( FALSE ) ;
+ break ;
+ }
+ }
+
+ KdPrint(("GetDnsServerAddress: Primary: %x, backup: %x\r\n",
+ pIpDnsServer[0], pIpDnsServer[1] )) ;
+
+}
+
+/*******************************************************************
+
+ NAME: GetNameServerAddress
+
+ SYNOPSIS: Gets the Win server for the specified Lana.
+
+ Or, if DHCP is installed and the Name server addresses aren't
+ found, we get them from DHCP
+
+ ENTRY: IpAddr - If we can get from DHCP, get form this address
+ pIpNameServer - Receives addresses if found (otherwise 0)
+
+ NOTES: This routine is only used by Snowball
+
+ HISTORY:
+ Johnl 21-Oct-1993 Created
+
+********************************************************************/
+
+void GetNameServerAddress( ULONG IpAddr,
+ PULONG pIpNameServer)
+{
+ UCHAR i ;
+ PUCHAR pchSrv = "NameServer$" ;
+ PUCHAR pchSrvNum;
+ UINT OptId;
+ LPTSTR pchString ;
+ TDI_STATUS TdiStatus ;
+ BOOL fPrimaryFound = FALSE;
+ ULONG Buff[COUNT_NS_ADDR] ;
+
+
+ OptId = 44; // NBNS Option
+ pchSrvNum = pchSrv + 10 ; // to overwrite '$' with 1,2,3 etc.
+
+
+ for ( i = 0; i < COUNT_NS_ADDR; i++)
+ {
+
+ pIpNameServer[i] = LOOP_BACK ;
+ *pchSrvNum = '1' + i;
+
+ if ( !CTEReadIniString( NULL, pchSrv, &pchString ) )
+ {
+ if ( ConvertDottedDecimalToUlong( pchString, &pIpNameServer[i] ))
+ {
+ //
+ // Bad IP address format
+ //
+ DbgPrint("GetNameServerAddress: ConvertDottedDecimalToUlong failed!\r\n") ;
+ pIpNameServer[i] = LOOP_BACK ;
+ }
+ else if ( i == 0 )
+ fPrimaryFound = TRUE ;
+
+ CTEFreeMem( pchString ) ;
+ }
+ }
+
+ //
+ // Not in the .ini file, try getting them from DHCP
+ //
+
+ if ( !fPrimaryFound )
+ {
+ ULONG Size = sizeof( Buff ) ;
+ TDI_STATUS tdistatus ;
+
+ tdistatus = DhcpQueryOption( IpAddr,
+ OptId,
+ &Buff,
+ &Size ) ;
+
+ switch ( tdistatus )
+ {
+ case TDI_SUCCESS:
+ case TDI_BUFFER_OVERFLOW: // May be more then one our buffer will hold
+ for ( i = 0; i < COUNT_NS_ADDR; i++ )
+ {
+ if ( Size >= (sizeof(ULONG)*(i+1)))
+ pIpNameServer[i] = htonl(Buff[i]) ;
+ }
+ break ;
+
+ case TDI_INVALID_PARAMETER: // Option not found
+ break ;
+
+ default:
+ ASSERT( FALSE ) ;
+ break ;
+ }
+ }
+
+ KdPrint(("GetNameServerAddress: Primary: %x, backup: %x\r\n",
+ pIpNameServer[0], pIpNameServer[1] )) ;
+
+}
+
+
+#pragma END_INIT
+#endif //!CHICAGO
+
+
diff --git a/private/ntos/nbt/vxd/wfwasm.asm b/private/ntos/nbt/vxd/wfwasm.asm
new file mode 100644
index 000000000..79b9cb818
--- /dev/null
+++ b/private/ntos/nbt/vxd/wfwasm.asm
@@ -0,0 +1,285 @@
+;*****************************************************************;
+;** Copyright(c) Microsoft Corp., 1988-1993 **;
+;*****************************************************************;
+;:ts=8
+ TITLE WFWASM.ASM - WFW Specific vnbt routines
+.XLIST
+;*** VNBT -- NetBios over TCP/IP VxD
+;
+;
+ .386p
+ include vmm.inc
+ include dosmgr.inc
+ include netvxd.inc
+ include vdhcp.inc
+ include debug.inc
+ include vtdi.inc
+
+ include vnbtd.inc
+ include vnetbios.inc
+.LIST
+
+IFNDEF CHICAGO
+
+EXTRN _GetDhcpOption:NEAR
+EXTRN NCB_Handler:NEAR
+
+VxD_ICODE_SEG
+
+public _NBTSectionName
+_NBTSectionName db 'NBT',0 ; Section in system.ini parameters are stored
+public _DNSSectionName
+_DNSSectionName db 'DNS',0 ; DNS Section in system.ini
+
+;****************************************************************************
+;** _GetProfileInt
+;
+; Reads a parameter from our system.ini file (INIT TIME ONLY!)
+;
+; Entry: See ReadParamParams
+;
+; Exit: Eax contains specified value or defaulted value
+;
+
+ReadParamParams struc
+ dd ? ; Return Address
+ dd ? ; Saved edi
+ dd ? ; Saved esi
+ dd ? ; ParametersHandle (unused)
+ValueName dd ? ; Pointer to value name string
+DefaultValue dd ? ; Value to use if not in .ini file
+MinimumValue dd ? ; Specified value must be >= MinimumValue
+
+ReadParamParams ends
+
+BeginProc _GetProfileInt
+ push edi
+ push esi
+
+ ;
+ ; Get the value from the system.ini file (if can't be found then eax
+ ; will contain the default value)
+ ;
+ mov eax, [esp].DefaultValue
+ mov esi, OFFSET32 _NBTSectionName
+ mov edi, [esp].ValueName
+ VMMCall Get_Profile_Decimal_Int
+
+ jnc GPI_Found
+
+ push eax ; Default value
+ push edi ; Value name
+ call _GetDhcpOption ; Returns DHCP value or default
+ add esp, 8
+
+GPI_Found:
+ ;
+ ; Does the value meet our standards?
+ ;
+ cmp eax, [esp].MinimumValue ; Unsigned comparison
+ ja RP10
+ mov eax, [esp].MinimumValue
+
+RP10:
+ pop esi
+ pop edi
+ ret
+EndProc _GetProfileInt
+
+;****************************************************************************
+;** _GetProfileHex
+;
+; Reads a hex parameter from our system.ini file (INIT TIME ONLY!)
+;
+; Entry: See ReadParamParams
+;
+; Exit: Eax contains specified value or defaulted value
+;
+
+ReadParamParams struc
+ dd ? ; Return Address
+ dd ? ; Saved edi
+ dd ? ; Saved esi
+ dd ? ; ParametersHandle (unused)
+ValueName dd ? ; Pointer to value name string
+DefaultValue dd ? ; Value to use if not in .ini file
+MinimumValue dd ? ; Specified value must be >= MinimumValue
+
+ReadParamParams ends
+
+BeginProc _GetProfileHex
+ push edi
+ push esi
+
+ ;
+ ; Get the value from the system.ini file (if can't be found then eax
+ ; will contain the default value)
+ ;
+ mov eax, [esp].DefaultValue
+ mov esi, OFFSET32 _NBTSectionName
+ mov edi, [esp].ValueName
+ VMMCall Get_Profile_Hex_Int
+
+ jnc GPH_Found
+
+ push eax ; Default value
+ push edi ; Value name
+ call _GetDhcpOption ; Returns DHCP value or default
+ add esp, 8
+
+GPH_Found:
+ ;
+ ; Does the value meet our standards?
+ ;
+ cmp eax, [esp].MinimumValue ; Unsigned comparison
+ ja RHP10
+ mov eax, [esp].MinimumValue
+
+RHP10:
+ pop esi
+ pop edi
+ ret
+EndProc _GetProfileHex
+
+
+;****************************************************************************
+;** _GetProfileString
+;
+; Reads a string from our system.ini file (INIT TIME ONLY!)
+;
+; Entry: See GetProfileStrParams structure
+;
+; Exit: Eax contains the found value or NULL if not found
+;
+; History:
+; 30-May-94 Koti
+; this function modified to accept name of the section
+; to look at as a parameter. Getting DNS server ipaddrs
+; from the DNS section in system.ini demanded this change
+;
+
+GetProfileStrParams struc
+ dd ? ; Return Address
+ dd ? ; saved edx
+ dd ? ; Saved edi
+ dd ? ; Saved esi
+gps_ValueName dd ? ; Pointer to value name string
+gps_DefaultValue dd ? ; Value to use if not in .ini file
+gps_SectionName dd ? ; Name of the section to look at (almost always NBT)
+GetProfileStrParams ends
+
+BeginProc _GetProfileString
+ push edx
+ push edi
+ push esi
+
+ ;
+ ; Get the value from the system.ini file (if can't be found then eax
+ ; will contain the default value)
+ ;
+ mov edx, [esp].gps_DefaultValue
+ mov esi, [esp].gps_SectionName
+ mov edi, [esp].gps_ValueName
+ VMMCall Get_Profile_String
+
+ jc GetProf10
+ mov eax, edx ; Success
+ jmp short GetProf20
+
+GetProf10:
+ mov eax, 0 ; Couldn't find the string
+
+GetProf20:
+
+ pop esi
+ pop edi
+ pop edx
+ ret
+EndProc _GetProfileString
+
+;****************************************************************************
+;** _RegisterLana
+;
+; Registers the requested lana with the VNetbios driver.
+;
+; Entry: [ESP+4] - Lana number to register
+;
+; Exit: EAX will be TRUE if successful, FALSE if not
+;
+; Uses:
+;
+BeginProc _RegisterLana
+
+ mov eax, [esp+4] ; Get the request lana to register
+
+ push ebx
+ push edx
+
+ mov ebx, 1 ; Take over RM lana
+ mov edx, NCB_Handler
+ VxDcall VNETBIOS_Register ; Carry set on failure
+ jnc RegLana10
+ mov eax, 0 ; Failed
+ jmp short RegLana20
+
+RegLana10:
+ mov eax, 1 ; Success
+
+RegLana20:
+ pop edx
+ pop ebx
+ ret
+
+EndProc _RegisterLana
+
+;****************************************************************************
+;** _DhcpSetInfo - Sets DHCP information
+;
+; Stub callout to the Dhcp driver
+;
+; Entry: [ESP+4] - Info type
+; [ESP+8] - IP Address of interest
+; [ESP+12]- Pointer to buffer
+; [ESP+16]- Pointer to buffer size
+;
+; INIT TIME ONLY!
+;
+
+BeginProc _DhcpSetInfo
+
+ VxdCall VDHCP_Get_Version
+ jnc DSI_Installed
+
+ mov eax, 26 ; DHCP not installed, return invalid param
+ ret
+
+DSI_Installed:
+ push ebp
+ mov ebp,esp
+
+ mov eax, [ebp+20] ; Buff size
+ push eax
+ mov eax, [ebp+16] ; Buff
+ push eax
+ mov eax, [ebp+12] ; IP Address
+ push eax
+ mov eax, [ebp+8] ; Info type
+ push eax
+
+ VxdCall VDHCP_Set_Info
+
+ add esp, 16
+
+ pop ebp
+ ret
+
+EndProc _DhcpSetInfo
+
+VxD_ICODE_ENDS
+
+ENDIF ;!CHICAGO
+
+END
+
+
+