749 lines
23 KiB
C
749 lines
23 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Tdiout.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
|
|||
|
This file represents the TDI interface on the bottom edge of NBT.
|
|||
|
The procedures herein conform to the TDI I/F spec. and then convert
|
|||
|
the information to NT specific Irps etc. This implementation can be
|
|||
|
changed out to run on another OS.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jim Stewart (Jimst) 10-2-92
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "precomp.h" // procedure headings
|
|||
|
|
|||
|
// function prototypes for completion routines used in this file
|
|||
|
NTSTATUS
|
|||
|
TdiSendDatagramCompletion(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP pIrp,
|
|||
|
IN PVOID pSendbufferMdl
|
|||
|
);
|
|||
|
NTSTATUS
|
|||
|
TcpConnectComplete(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP pIrp,
|
|||
|
IN PVOID pContext
|
|||
|
);
|
|||
|
NTSTATUS
|
|||
|
TcpDisconnectComplete(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP pIrp,
|
|||
|
IN PVOID pContext
|
|||
|
);
|
|||
|
NTSTATUS
|
|||
|
SendSessionCompletionRoutine(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP pIrp,
|
|||
|
IN PVOID pContext
|
|||
|
);
|
|||
|
|
|||
|
// DEBUG
|
|||
|
VOID
|
|||
|
CheckIrpList(
|
|||
|
);
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
TdiSendDatagram(
|
|||
|
IN PTDI_REQUEST pRequestInfo,
|
|||
|
IN PTDI_CONNECTION_INFORMATION pSendDgramInfo,
|
|||
|
IN ULONG SendLength,
|
|||
|
OUT PULONG pSentSize,
|
|||
|
IN tDGRAM_SEND_TRACKING *pDgramTracker
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sends a datagram to the transport
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pSendBuffer - this is really an Mdl in NT land. It must be tacked on
|
|||
|
the end of the Mdl created for the Nbt datagram header.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PIRP pRequestIrp;
|
|||
|
PMDL pMdl;
|
|||
|
PDEVICE_OBJECT pDeviceObject;
|
|||
|
PFILE_OBJECT pFileObject;
|
|||
|
PVOID pCompletionRoutine;
|
|||
|
tBUFFER *pSendBuffer = &pDgramTracker->SendBuffer;
|
|||
|
|
|||
|
// get an Irp to send the message in
|
|||
|
pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
|
|||
|
pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
|
|||
|
|
|||
|
status = GetIrp(&pRequestIrp); // get an Irp from the list
|
|||
|
if (NT_SUCCESS(status))
|
|||
|
{
|
|||
|
pRequestIrp->CancelRoutine = NULL;
|
|||
|
|
|||
|
// set up the completion routine passed in from Udp Send using the APC
|
|||
|
// fields in the Irp that would normally be used to complete the request
|
|||
|
// back to the client - although we are really the client here so we can
|
|||
|
// use these fields our self!
|
|||
|
pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
|
|||
|
(PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
|
|||
|
pRequestIrp->Overlay.AsynchronousParameters.UserApcContext = (PVOID)pRequestInfo->RequestContext;
|
|||
|
|
|||
|
// Allocate a MDL and set the head sizes correctly
|
|||
|
if (!(pMdl = IoAllocateMdl (pSendBuffer->pDgramHdr, pSendBuffer->HdrLength, FALSE, FALSE, NULL)))
|
|||
|
{
|
|||
|
REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
|
|||
|
ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
|
|||
|
&pRequestIrp->Tail.Overlay.ListEntry,
|
|||
|
&NbtConfig.LockInfo.SpinLock);
|
|||
|
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIOUT)
|
|||
|
KdPrint(("Nbt.TdiSendDatagram: Failed to get an Irp"));
|
|||
|
}
|
|||
|
|
|||
|
// tack the client's send buffer (MDL) onto the end of the datagram header
|
|||
|
// Mdl, and then pass the irp on downward to the transport
|
|||
|
if (NT_SUCCESS(status) && pSendBuffer->pBuffer) {
|
|||
|
pMdl->Next = IoAllocateMdl (pSendBuffer->pBuffer, pSendBuffer->Length, FALSE, FALSE, NULL);
|
|||
|
if (pMdl->Next == NULL) {
|
|||
|
REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
|
|||
|
ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
|
|||
|
&pRequestIrp->Tail.Overlay.ListEntry,
|
|||
|
&NbtConfig.LockInfo.SpinLock);
|
|||
|
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
IoFreeMdl(pMdl);
|
|||
|
pMdl = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
if (pRequestInfo->RequestNotifyObject) // call the completion routine (if there is one)
|
|||
|
{
|
|||
|
NBT_DEREFERENCE_DEVICE (pDgramTracker->pDeviceContext, REF_DEV_UDP_SEND, FALSE);
|
|||
|
|
|||
|
(*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
|
|||
|
((PVOID)pRequestInfo->RequestContext,
|
|||
|
STATUS_INSUFFICIENT_RESOURCES,
|
|||
|
0L);
|
|||
|
}
|
|||
|
|
|||
|
return(STATUS_PENDING); // so the Irp is not completed twice.
|
|||
|
}
|
|||
|
|
|||
|
// Map the pages in memory...
|
|||
|
ASSERT(!pSendBuffer->pBuffer || pMdl->Next);
|
|||
|
MmBuildMdlForNonPagedPool(pMdl);
|
|||
|
if (pMdl->Next) {
|
|||
|
MmBuildMdlForNonPagedPool(pMdl->Next);
|
|||
|
}
|
|||
|
pCompletionRoutine = TdiSendDatagramCompletion;
|
|||
|
|
|||
|
// store some context stuff in the Irp stack so we can call the completion
|
|||
|
// routine set by the Udpsend code...
|
|||
|
TdiBuildSendDatagram (pRequestIrp,
|
|||
|
pDeviceObject,
|
|||
|
pFileObject,
|
|||
|
pCompletionRoutine,
|
|||
|
(PVOID)pMdl->Next, // The completion routine will know that we have allocated an extra MDL
|
|||
|
pMdl,
|
|||
|
SendLength,
|
|||
|
pSendDgramInfo);
|
|||
|
|
|||
|
CHECK_COMPLETION(pRequestIrp);
|
|||
|
status = IoCallDriver(pDeviceObject,pRequestIrp);
|
|||
|
*pSentSize = SendLength; // Fill in the SentSize
|
|||
|
|
|||
|
// The transport always completes the IRP, so as long as the irp made it
|
|||
|
// to the transport it got completed. The return code from the transport
|
|||
|
// does not indicate if the irp was completed or not. The real status
|
|||
|
// of the operation is in the Irp Iostatus return code.
|
|||
|
// What we need to do is make sure NBT does not complete the irp AND the
|
|||
|
// transport complete the Irp. Therefore this routine returns
|
|||
|
// status pending if the Irp was passed to the transport, regardless of
|
|||
|
// the return code from the transport. This return code signals the caller
|
|||
|
// that the irp will be completed via the completion routine and the
|
|||
|
// actual status of the send can be found in the Irpss IoStatus.Status
|
|||
|
// variable.
|
|||
|
//
|
|||
|
// If the Caller of this routine gets a bad return code, they can assume
|
|||
|
// that this routine failed to give the Irp to the transport and it
|
|||
|
// is safe for them to complete the Irp themselves.
|
|||
|
//
|
|||
|
// If the Completion routine is set to null, then there is no danger
|
|||
|
// of the irp completing twice and this routine will return the transport
|
|||
|
// return code in that case.
|
|||
|
|
|||
|
if (pRequestInfo->RequestNotifyObject)
|
|||
|
{
|
|||
|
return(STATUS_PENDING);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return(status);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
TdiSendDatagramCompletion(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP pIrp,
|
|||
|
IN PVOID pSendbufferMdl
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles the completion of a datagram send to the transport.
|
|||
|
It must call the client completion routine and free the Irp and Mdl.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - success or not
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KIRQL OldIrq;
|
|||
|
tDGRAM_SEND_TRACKING *pTracker = pIrp->Overlay.AsynchronousParameters.UserApcContext;
|
|||
|
tDEVICECONTEXT *pDeviceContext;
|
|||
|
|
|||
|
// check for a completion routine of the clients to call...
|
|||
|
if (pIrp->Overlay.AsynchronousParameters.UserApcRoutine)
|
|||
|
{
|
|||
|
//
|
|||
|
// The Tracker can be free'ed in the routine below, so save the Device ptr
|
|||
|
//
|
|||
|
pDeviceContext = pTracker->pDeviceContext;
|
|||
|
|
|||
|
(*((NBT_COMPLETION)pIrp->Overlay.AsynchronousParameters.UserApcRoutine))
|
|||
|
((PVOID)pIrp->Overlay.AsynchronousParameters.UserApcContext,
|
|||
|
pIrp->IoStatus.Status,
|
|||
|
(ULONG)pIrp->IoStatus.Information); // sent length
|
|||
|
|
|||
|
NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_UDP_SEND, FALSE);
|
|||
|
}
|
|||
|
|
|||
|
// Don't depend on pIrp->MdlAddress->Next which may occassionally changed by others
|
|||
|
ASSERT((PMDL)pSendbufferMdl == pIrp->MdlAddress->Next);
|
|||
|
if (pSendbufferMdl) {
|
|||
|
IoFreeMdl((PMDL)pSendbufferMdl);
|
|||
|
}
|
|||
|
// deallocate the MDL.. this is done by the IO subsystem in IoCompleteRequest
|
|||
|
pIrp->MdlAddress->Next = NULL;
|
|||
|
IoFreeMdl(pIrp->MdlAddress);
|
|||
|
REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
|
|||
|
ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
|
|||
|
&pIrp->Tail.Overlay.ListEntry,
|
|||
|
&NbtConfig.LockInfo.SpinLock);
|
|||
|
|
|||
|
// return this status to stop the IO subsystem from further processing the
|
|||
|
// IRP - i.e. trying to complete it back to the initiating thread! -since
|
|||
|
// there is no initiating thread - we are the initiator
|
|||
|
return(STATUS_MORE_PROCESSING_REQUIRED);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
PIRP
|
|||
|
NTAllocateNbtIrp(
|
|||
|
IN PDEVICE_OBJECT DeviceObject
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine allocates an irp by calling the IO system, and then it
|
|||
|
undoes the queuing of the irp to the current thread, since these are
|
|||
|
NBTs own irps, and should not be attached to a thread.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - success or not
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PIRP pIrp;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// call the IO subsystem to allocate the irp
|
|||
|
|
|||
|
pIrp = IoAllocateIrp(DeviceObject->StackSize,FALSE);
|
|||
|
|
|||
|
if (!pIrp)
|
|||
|
{
|
|||
|
return(NULL);
|
|||
|
}
|
|||
|
//
|
|||
|
// Simply return a pointer to the packet.
|
|||
|
//
|
|||
|
|
|||
|
return pIrp;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
TdiConnect(
|
|||
|
IN PTDI_REQUEST pRequestInfo,
|
|||
|
IN ULONG_PTR lTimeout,
|
|||
|
IN PTDI_CONNECTION_INFORMATION pSendInfo,
|
|||
|
IN PIRP pClientIrp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sends a connect request to the tranport provider, to setup
|
|||
|
a connection to the other side...
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PIRP pRequestIrp;
|
|||
|
PDEVICE_OBJECT pDeviceObject;
|
|||
|
PFILE_OBJECT pFileObject;
|
|||
|
|
|||
|
// get an Irp to send the message in
|
|||
|
pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
|
|||
|
pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
|
|||
|
|
|||
|
// get an Irp from the list
|
|||
|
status = GetIrp(&pRequestIrp);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIOUT)
|
|||
|
KdPrint(("Nbt.TdiConnect: Failed to get an Irp"));
|
|||
|
// call the completion routine with this status
|
|||
|
(*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
|
|||
|
((PVOID)pRequestInfo->RequestContext,
|
|||
|
STATUS_INSUFFICIENT_RESOURCES,
|
|||
|
0L);
|
|||
|
return(STATUS_PENDING);
|
|||
|
}
|
|||
|
pRequestIrp->CancelRoutine = NULL;
|
|||
|
|
|||
|
// set up the completion routine passed in from Tcp SessionStart using the APC
|
|||
|
// fields in the Irp that would normally be used to complete the request
|
|||
|
// back to the client - although we are really the client here so we can
|
|||
|
// use these fields ourselves
|
|||
|
pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
|
|||
|
(PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
|
|||
|
pRequestIrp->Overlay.AsynchronousParameters.UserApcContext =
|
|||
|
(PVOID)pRequestInfo->RequestContext;
|
|||
|
|
|||
|
// store some context stuff in the Irp stack so we can call the completion
|
|||
|
// routine set by the Udpsend code...
|
|||
|
TdiBuildConnect(
|
|||
|
pClientIrp,
|
|||
|
pDeviceObject,
|
|||
|
pFileObject,
|
|||
|
TcpConnectComplete,
|
|||
|
(PVOID)pRequestIrp, //context value passed to completion routine
|
|||
|
lTimeout, // use timeout on connect
|
|||
|
pSendInfo,
|
|||
|
NULL);
|
|||
|
|
|||
|
pRequestIrp->MdlAddress = NULL;
|
|||
|
|
|||
|
CHECK_COMPLETION(pClientIrp);
|
|||
|
status = IoCallDriver(pDeviceObject,pClientIrp);
|
|||
|
|
|||
|
// the transport always completes the IRP, so we always return status pending
|
|||
|
return(STATUS_PENDING);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
TdiDisconnect(
|
|||
|
IN PTDI_REQUEST pRequestInfo,
|
|||
|
IN PVOID lTimeout,
|
|||
|
IN ULONG Flags,
|
|||
|
IN PTDI_CONNECTION_INFORMATION pSendInfo,
|
|||
|
IN PCTE_IRP pClientIrp,
|
|||
|
IN BOOLEAN Wait
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sends a connect request to the tranport provider, to setup
|
|||
|
a connection to the other side...
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pClientIrp - this is the irp that the client used when it issued an
|
|||
|
NbtDisconnect. We pass this irp to the transport so that
|
|||
|
the client can do a Ctrl C and cancel the irp if the
|
|||
|
disconnect takes too long.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PIRP pRequestIrp;
|
|||
|
PDEVICE_OBJECT pDeviceObject;
|
|||
|
PFILE_OBJECT pFileObject;
|
|||
|
|
|||
|
// get an Irp to send the message in
|
|||
|
pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
|
|||
|
pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
|
|||
|
|
|||
|
status = GetIrp(&pRequestIrp);
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIOUT)
|
|||
|
KdPrint(("Nbt.TdiDisconnect: Failed to get an Irp"));
|
|||
|
// call the completion routine will this status
|
|||
|
(*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
|
|||
|
((PVOID)pRequestInfo->RequestContext,
|
|||
|
STATUS_INSUFFICIENT_RESOURCES,
|
|||
|
0L);
|
|||
|
return(STATUS_PENDING);
|
|||
|
}
|
|||
|
if (!pClientIrp)
|
|||
|
{
|
|||
|
// if no client irp was passed in, then just use our Irp
|
|||
|
pClientIrp = pRequestIrp;
|
|||
|
}
|
|||
|
pRequestIrp->CancelRoutine = NULL;
|
|||
|
|
|||
|
// set up the completion routine passed in from Tcp SessionStart using the APC
|
|||
|
// fields in the Irp that would normally be used to complete the request
|
|||
|
// back to the client - although we are really the client here so we can
|
|||
|
// use these fields ourselves
|
|||
|
pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
|
|||
|
(PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
|
|||
|
pRequestIrp->Overlay.AsynchronousParameters.UserApcContext =
|
|||
|
(PVOID)pRequestInfo->RequestContext;
|
|||
|
|
|||
|
// store some context stuff in the Irp stack so we can call the completion
|
|||
|
// routine set by the Udpsend code...
|
|||
|
// Note that pRequestIrp is passed to the completion routine as a context
|
|||
|
// value so we will know the routine to call for the client's completion.
|
|||
|
TdiBuildDisconnect(
|
|||
|
pClientIrp,
|
|||
|
pDeviceObject,
|
|||
|
pFileObject,
|
|||
|
TcpConnectComplete,
|
|||
|
(PVOID)pRequestIrp, //context value passed to completion routine
|
|||
|
lTimeout,
|
|||
|
Flags,
|
|||
|
NULL, // send connection info
|
|||
|
NULL); // return connection info
|
|||
|
|
|||
|
pRequestIrp->MdlAddress = NULL;
|
|||
|
|
|||
|
// if Wait is set, then this means do a synchronous disconnect and block
|
|||
|
// until the irp is returned.
|
|||
|
//
|
|||
|
if (Wait)
|
|||
|
{
|
|||
|
status = SubmitTdiRequest(pFileObject,pClientIrp);
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIOUT)
|
|||
|
KdPrint (("Nbt.TdiDisconnect: ERROR -- SubmitTdiRequest returned <%x>\n", status));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// return the irp to its pool
|
|||
|
//
|
|||
|
REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
|
|||
|
ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
|
|||
|
&pRequestIrp->Tail.Overlay.ListEntry,
|
|||
|
&NbtConfig.LockInfo.SpinLock);
|
|||
|
return(status);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
CHECK_COMPLETION(pClientIrp);
|
|||
|
status = IoCallDriver(pDeviceObject,pClientIrp);
|
|||
|
// the transport always completes the IRP, so we always return status pending
|
|||
|
return(STATUS_PENDING);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
TcpConnectComplete(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP pIrp,
|
|||
|
IN PVOID pContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles the completion of a TCP session setup. The TCP
|
|||
|
connection is either setup or not depending on the status returned here.
|
|||
|
It must called the clients completion routine (in udpsend.c). Which should
|
|||
|
look after sending the NetBios sesion startup pdu across the TCP connection.
|
|||
|
|
|||
|
The pContext value is actually one of NBTs irps that is JUST used to store
|
|||
|
the calling routines completion routine. The real Irp used is the original
|
|||
|
client's irp. This is done so that IoCancelIrp will cancel the connect
|
|||
|
properly.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - success or not
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KIRQL OldIrq;
|
|||
|
PIRP pMyIrp;
|
|||
|
|
|||
|
pMyIrp = (PIRP)pContext;
|
|||
|
|
|||
|
// check for a completion routine of the clients to call...
|
|||
|
if (pMyIrp->Overlay.AsynchronousParameters.UserApcRoutine)
|
|||
|
{
|
|||
|
(*((NBT_COMPLETION)pMyIrp->Overlay.AsynchronousParameters.UserApcRoutine))
|
|||
|
((PVOID)pMyIrp->Overlay.AsynchronousParameters.UserApcContext,
|
|||
|
pIrp->IoStatus.Status,
|
|||
|
0L);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
REMOVE_FROM_LIST(&pMyIrp->ThreadListEntry);
|
|||
|
ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
|
|||
|
&pMyIrp->Tail.Overlay.ListEntry,
|
|||
|
&NbtConfig.LockInfo.SpinLock);
|
|||
|
|
|||
|
// return this status to stop the IO subsystem from further processing the
|
|||
|
// IRP - i.e. trying to complete it back to the initiating thread! -since
|
|||
|
// there is not initiating thread - we are the initiator
|
|||
|
return(STATUS_MORE_PROCESSING_REQUIRED);
|
|||
|
|
|||
|
}
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
TdiSend(
|
|||
|
IN PTDI_REQUEST pRequestInfo,
|
|||
|
IN USHORT sFlags,
|
|||
|
IN ULONG SendLength,
|
|||
|
OUT PULONG pSentSize,
|
|||
|
IN tBUFFER *pSendBuffer,
|
|||
|
IN ULONG Flags
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sends a packet to the transport on a TCP connection
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pSendBuffer - this is really an Mdl in NT land. It must be tacked on
|
|||
|
the end of the Mdl created for the Nbt datagram header.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PIRP pRequestIrp;
|
|||
|
PMDL pMdl;
|
|||
|
PDEVICE_OBJECT pDeviceObject;
|
|||
|
PFILE_OBJECT pFileObject;
|
|||
|
|
|||
|
// get an Irp to send the message in
|
|||
|
pFileObject = (PFILE_OBJECT)pRequestInfo->Handle.AddressHandle;
|
|||
|
pDeviceObject = IoGetRelatedDeviceObject(pFileObject);
|
|||
|
|
|||
|
// get an Irp from the list
|
|||
|
status = GetIrp(&pRequestIrp);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status))
|
|||
|
{
|
|||
|
IF_DBG(NBT_DEBUG_TDIOUT)
|
|||
|
KdPrint(("Nbt.TdiSend: Failed to get an Irp"));
|
|||
|
// call the completion routine with this status
|
|||
|
if (pRequestInfo->RequestNotifyObject)
|
|||
|
{
|
|||
|
(*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
|
|||
|
((PVOID)pRequestInfo->RequestContext,
|
|||
|
STATUS_INSUFFICIENT_RESOURCES,
|
|||
|
0L);
|
|||
|
}
|
|||
|
|
|||
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
pRequestIrp->CancelRoutine = NULL;
|
|||
|
|
|||
|
|
|||
|
// set up the completion routine passed in from Udp Send using the APC
|
|||
|
// fields in the Irp that would normally be used to complete the request
|
|||
|
// back to the client - although we are really the client here so we can
|
|||
|
// use these fields our self!
|
|||
|
pRequestIrp->Overlay.AsynchronousParameters.UserApcRoutine =
|
|||
|
(PIO_APC_ROUTINE)pRequestInfo->RequestNotifyObject;
|
|||
|
pRequestIrp->Overlay.AsynchronousParameters.UserApcContext =
|
|||
|
(PVOID)pRequestInfo->RequestContext;
|
|||
|
|
|||
|
|
|||
|
// get the MDL that is currently linked to the IRP (i.e. created at the
|
|||
|
// same time that we created the IRP list. Set the sizes correctly in
|
|||
|
// the MDL header.
|
|||
|
pMdl = IoAllocateMdl(
|
|||
|
pSendBuffer->pDgramHdr,
|
|||
|
pSendBuffer->HdrLength,
|
|||
|
FALSE,
|
|||
|
FALSE,
|
|||
|
NULL);
|
|||
|
|
|||
|
if (!pMdl)
|
|||
|
{
|
|||
|
REMOVE_FROM_LIST(&pRequestIrp->ThreadListEntry);
|
|||
|
ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
|
|||
|
&pRequestIrp->Tail.Overlay.ListEntry,
|
|||
|
&NbtConfig.LockInfo.SpinLock);
|
|||
|
|
|||
|
// call the completion routine will this status
|
|||
|
if (pRequestInfo->RequestNotifyObject)
|
|||
|
{
|
|||
|
(*((NBT_COMPLETION)pRequestInfo->RequestNotifyObject))
|
|||
|
((PVOID)pRequestInfo->RequestContext,
|
|||
|
STATUS_INSUFFICIENT_RESOURCES,
|
|||
|
0L);
|
|||
|
}
|
|||
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|||
|
}
|
|||
|
|
|||
|
// Map the pages in memory...
|
|||
|
MmBuildMdlForNonPagedPool(pMdl);
|
|||
|
|
|||
|
TdiBuildSend(
|
|||
|
pRequestIrp,
|
|||
|
pDeviceObject,
|
|||
|
pFileObject,
|
|||
|
SendSessionCompletionRoutine,
|
|||
|
NULL, //context value passed to completion routine
|
|||
|
pMdl,
|
|||
|
sFlags,
|
|||
|
SendLength); // include session hdr length (ULONG)
|
|||
|
//
|
|||
|
// tack the Client's buffer on the end, if there is one
|
|||
|
//
|
|||
|
if (pSendBuffer->Length)
|
|||
|
{
|
|||
|
pMdl->Next = pSendBuffer->pBuffer;
|
|||
|
}
|
|||
|
|
|||
|
CHECK_COMPLETION(pRequestIrp);
|
|||
|
status = IoCallDriver(pDeviceObject,pRequestIrp);
|
|||
|
|
|||
|
*pSentSize = SendLength; // the size we attempted to send
|
|||
|
|
|||
|
return(status);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//----------------------------------------------------------------------------
|
|||
|
NTSTATUS
|
|||
|
SendSessionCompletionRoutine(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP pIrp,
|
|||
|
IN PVOID pContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine handles the completion of a send to the transport.
|
|||
|
It must call any client supplied completion routine and free the Irp
|
|||
|
and Mdl back to its pool.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - success or not
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
KIRQL OldIrq;
|
|||
|
|
|||
|
//
|
|||
|
// check for a completion routine of the clients to call...
|
|||
|
//
|
|||
|
if (pIrp->Overlay.AsynchronousParameters.UserApcRoutine)
|
|||
|
{
|
|||
|
(*((NBT_COMPLETION)pIrp->Overlay.AsynchronousParameters.UserApcRoutine))
|
|||
|
((PVOID)pIrp->Overlay.AsynchronousParameters.UserApcContext,
|
|||
|
pIrp->IoStatus.Status,
|
|||
|
(ULONG)pIrp->IoStatus.Information); // sent length
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
IoFreeMdl(pIrp->MdlAddress);
|
|||
|
|
|||
|
REMOVE_FROM_LIST(&pIrp->ThreadListEntry);
|
|||
|
ExInterlockedInsertTailList(&NbtConfig.IrpFreeList,
|
|||
|
&pIrp->Tail.Overlay.ListEntry,
|
|||
|
&NbtConfig.LockInfo.SpinLock);
|
|||
|
//
|
|||
|
// return this status to stop the IO subsystem from further processing the
|
|||
|
// IRP - i.e. trying to complete it back to the initiating thread! -since
|
|||
|
// there is no initiating thread - we are the initiator
|
|||
|
//
|
|||
|
return(STATUS_MORE_PROCESSING_REQUIRED);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|