summaryrefslogtreecommitdiffstats
path: root/private/ntos/nbt/nt/ntisol.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nbt/nt/ntisol.c')
-rw-r--r--private/ntos/nbt/nt/ntisol.c4873
1 files changed, 4873 insertions, 0 deletions
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;
+}
+