summaryrefslogtreecommitdiffstats
path: root/private/ntos/nbt/nt
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nbt/nt')
-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
28 files changed, 23435 insertions, 0 deletions
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);
+}