windows-nt/Source/XPSP1/NT/net/tdi/sample/sys/buffer.cpp
2020-09-26 16:20:57 +08:00

501 lines
14 KiB
C++

/////////////////////////////////////////////////////////
//
// Copyright (c) 2001 Microsoft Corporation
//
// Module Name:
// buffer
//
// Abstract:
// This module contains code which deals with receiving
// data via posted user mode buffers
//
//////////////////////////////////////////////////////////
#include "sysvars.h"
//////////////////////////////////////////////////////////////
// private constants, types, and prototypes
//////////////////////////////////////////////////////////////
const PCHAR strFunc1 = "TSPostReceiveBuffer";
//const PCHAR strFunc2 = "TSFetchReceiveBuffer";
const PCHAR strFuncP1 = "TSSampleReceiveBufferComplete";
//
// receive completion context. Also used to track what buffers have
// been posted
//
struct USERBUF_INFO
{
USERBUF_INFO *pNextUserBufInfo; // next one in chain
PMDL pLowerMdl; // mdl for lower irp
PIRP pLowerIrp; // so can abort it...
TDI_EVENT TdiEventCompleted; // abort completed
ULONG ulBytesTransferred; // #bytes stored in mdl
PUCHAR pucUserModeBuffer;
PTDI_CONNECTION_INFORMATION
pReceiveTdiConnectInfo;
PTDI_CONNECTION_INFORMATION
pReturnTdiConnectInfo;
};
typedef USERBUF_INFO *PUSERBUF_INFO;
//
// completion function
//
TDI_STATUS
TSReceiveBufferComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
);
//////////////////////////////////////////////////////////////
// public functions
//////////////////////////////////////////////////////////////
// --------------------------------------------------------
//
// Function: TSPostReceiveBuffer
//
// Arguments: pGenericHeader -- AddressObject or Endpoint to post buffer for
// pSendBuffer -- rest of arguments
//
// Returns: status of operation (STATUS_SUCCESS or a failure)
//
// Descript: This function posts a user mode buffer for receiving either
// a datagram or a packet over a connection. The buffer will
// be retrieved later by TSFetchReceiveBuffer
//
// --------------------------------------------------------
NTSTATUS
TSPostReceiveBuffer(PGENERIC_HEADER pGenericHeader,
PSEND_BUFFER pSendBuffer)
{
ULONG ulDataLength = pSendBuffer->COMMAND_ARGS.SendArgs.ulBufferLength;
PUCHAR pucDataBuffer = pSendBuffer->COMMAND_ARGS.SendArgs.pucUserModeBuffer;
//
// show debug, if it is turned on
//
if (ulDebugLevel & ulDebugShowCommand)
{
DebugPrint3("\nCommand = ulPOSTRECEIVEBUFFER\n"
"FileObject = %p\n"
"DataLength = %u\n"
"Buffer = %p\n",
pGenericHeader,
ulDataLength,
pucDataBuffer);
}
//
// make sure we have a valid object to run on
//
PADDRESS_OBJECT pAddressObject;
PENDPOINT_OBJECT pEndpoint;
if (pGenericHeader->ulSignature == ulEndpointObject)
{
pEndpoint = (PENDPOINT_OBJECT)pGenericHeader;
if (pEndpoint->fIsConnected)
{
pAddressObject = pEndpoint->pAddressObject;
}
else
{
return STATUS_UNSUCCESSFUL;
}
}
else
{
pEndpoint = NULL;
pAddressObject = (PADDRESS_OBJECT)pGenericHeader;
}
//
// attempt to lock down the memory
//
PMDL pReceiveMdl = TSMakeMdlForUserBuffer(pucDataBuffer,
ulDataLength,
IoModifyAccess);
if (!pReceiveMdl)
{
return STATUS_UNSUCCESSFUL;
}
//
// allocate our context
//
PUSERBUF_INFO pUserBufInfo = NULL;
PTDI_CONNECTION_INFORMATION pReceiveTdiConnectInfo = NULL;
PTDI_CONNECTION_INFORMATION pReturnTdiConnectInfo = NULL;
PIRP pLowerIrp = NULL;
//
// our context
//
if ((TSAllocateMemory((PVOID *)&pUserBufInfo,
sizeof(USERBUF_INFO),
strFunc1,
"UserBufInfo")) != STATUS_SUCCESS)
{
goto cleanup;
}
//
// do path specific allocations
//
if (pEndpoint)
{
pLowerIrp = TSAllocateIrp(pEndpoint->GenHead.pDeviceObject,
NULL);
}
else
{
//
// for datagrams, need the connection information structures
//
if ((TSAllocateMemory((PVOID *)&pReceiveTdiConnectInfo,
sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TRANSADDR),
strFunc1,
"ReceiveTdiConnectionInformation")) != STATUS_SUCCESS)
{
goto cleanup;
}
if ((TSAllocateMemory((PVOID *)&pReturnTdiConnectInfo,
sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TRANSADDR),
strFunc1,
"ReturnTdiConnectionInformation")) != STATUS_SUCCESS)
{
goto cleanup;
}
pLowerIrp = TSAllocateIrp(pAddressObject->GenHead.pDeviceObject,
NULL);
}
//
// everything is allocated at this point...
//
if (pLowerIrp)
{
//
// common code -- mostly dealing with puserbuf structure
// First, add it to the linked list
//
TSAcquireSpinLock(&pAddressObject->TdiSpinLock);
if (pAddressObject->pTailUserBufInfo)
{
pAddressObject->pTailUserBufInfo->pNextUserBufInfo = pUserBufInfo;
}
else
{
pAddressObject->pHeadUserBufInfo = pUserBufInfo;
}
pAddressObject->pTailUserBufInfo = pUserBufInfo;
TSReleaseSpinLock(&pAddressObject->TdiSpinLock);
//
// and fill in all fields that we can
//
pUserBufInfo->pLowerMdl = pReceiveMdl;
pUserBufInfo->pLowerIrp = pLowerIrp;
pUserBufInfo->ulBytesTransferred = 0;
pUserBufInfo->pucUserModeBuffer = pucDataBuffer;
pUserBufInfo->pReceiveTdiConnectInfo = pReceiveTdiConnectInfo;
pUserBufInfo->pReturnTdiConnectInfo = pReturnTdiConnectInfo;
TSInitializeEvent(&pUserBufInfo->TdiEventCompleted);
//
// now do what is necessary for each path..
//
if (pEndpoint)
{
//
// set up the irp for the call
//
#pragma warning(disable: CONSTANT_CONDITIONAL)
TdiBuildReceive(pLowerIrp,
pEndpoint->GenHead.pDeviceObject,
pEndpoint->GenHead.pFileObject,
TSReceiveBufferComplete,
pUserBufInfo,
pReceiveMdl,
0, // flags
ulDataLength);
#pragma warning(default: CONSTANT_CONDITIONAL)
NTSTATUS lStatus = IoCallDriver(pEndpoint->GenHead.pDeviceObject,
pLowerIrp);
if ((!NT_SUCCESS(lStatus)) && (ulDebugLevel & ulDebugShowCommand))
{
DebugPrint2(("%s: unexpected status for IoCallDriver [0x%08x]\n"),
strFunc1,
lStatus);
}
}
//
// else a datagram
//
else
{
pReturnTdiConnectInfo->RemoteAddress = (PUCHAR)pReturnTdiConnectInfo
+ sizeof(TDI_CONNECTION_INFORMATION);
pReturnTdiConnectInfo->RemoteAddressLength = ulMAX_TABUFFER_LENGTH;
//
// set up the irp for the call
//
#pragma warning(disable: CONSTANT_CONDITIONAL)
TdiBuildReceiveDatagram(pLowerIrp,
pAddressObject->GenHead.pDeviceObject,
pAddressObject->GenHead.pFileObject,
TSReceiveBufferComplete,
pUserBufInfo,
pReceiveMdl,
ulDataLength,
pReceiveTdiConnectInfo,
pReturnTdiConnectInfo,
TDI_RECEIVE_NORMAL);
#pragma warning(default: CONSTANT_CONDITIONAL)
NTSTATUS lStatus = IoCallDriver(pAddressObject->GenHead.pDeviceObject,
pLowerIrp);
if ((!NT_SUCCESS(lStatus)) && (ulDebugLevel & ulDebugShowCommand))
{
DebugPrint2(("%s: unexpected status for IoCallDriver [0x%08x]\n"),
strFunc1,
lStatus);
}
}
return STATUS_SUCCESS;
}
//
// get here if there was an allocation failure
// need to clean up everything else...
//
cleanup:
if (pUserBufInfo)
{
TSFreeMemory(pUserBufInfo);
}
if (pReceiveTdiConnectInfo)
{
TSFreeMemory(pReceiveTdiConnectInfo);
}
if (pReturnTdiConnectInfo)
{
TSFreeMemory(pReturnTdiConnectInfo);
}
TSFreeUserBuffer(pReceiveMdl);
return STATUS_INSUFFICIENT_RESOURCES;
}
// --------------------------------------------------------
//
// Function: TSFetchReceiveBuffer
//
// Arguments: pGenericHeader -- AddressObject or Endpoint to fetch buffer for
// pReceiveBuffer -- for storing actual results
//
// Returns: status of operation (STATUS_SUCCESS)
//
// Descript: This function retrieves the user mode buffer posted earlier
// by function TSPostReceiveBuffer
//
// --------------------------------------------------------
NTSTATUS
TSFetchReceiveBuffer(PGENERIC_HEADER pGenericHeader,
PRECEIVE_BUFFER pReceiveBuffer)
{
//
// show debug, if it is turned on
//
if (ulDebugLevel & ulDebugShowCommand)
{
DebugPrint1("\nCommand = ulFETCHRECEIVEBUFFER\n"
"FileObject = %p\n",
pGenericHeader);
}
//
// make sure we have a valid object to run on
//
PADDRESS_OBJECT pAddressObject;
if (pGenericHeader->ulSignature == ulEndpointObject)
{
PENDPOINT_OBJECT pEndpoint = (PENDPOINT_OBJECT)pGenericHeader;
//
// note: it is possible that connection has been broken but that
// the buffer is still posted
//
pAddressObject = pEndpoint->pAddressObject;
if (!pAddressObject)
{
return STATUS_UNSUCCESSFUL;
}
}
else
{
pAddressObject = (PADDRESS_OBJECT)pGenericHeader;
}
//
// ok, we got the address object. See if there are any user buffers
// attached to it...
//
TSAcquireSpinLock(&pAddressObject->TdiSpinLock);
PUSERBUF_INFO pUserBufInfo = pAddressObject->pHeadUserBufInfo;
if (pUserBufInfo)
{
if (pUserBufInfo->pNextUserBufInfo)
{
pAddressObject->pHeadUserBufInfo = pUserBufInfo->pNextUserBufInfo;
}
else
{
pAddressObject->pHeadUserBufInfo = NULL;
pAddressObject->pTailUserBufInfo = NULL;
}
}
TSReleaseSpinLock(&pAddressObject->TdiSpinLock);
if (!pUserBufInfo)
{
return STATUS_UNSUCCESSFUL;
}
//
// ok, we got our buffer. See if it has completed
// or if we need to abort it
//
if (pUserBufInfo->pLowerIrp)
{
IoCancelIrp(pUserBufInfo->pLowerIrp);
TSWaitEvent(&pUserBufInfo->TdiEventCompleted);
}
//
// it has finished. stuff the address and length into the receive
// buffer, delete the UserBufInfo structure, and go home
//
pReceiveBuffer->RESULTS.RecvDgramRet.ulBufferLength = pUserBufInfo->ulBytesTransferred;
pReceiveBuffer->RESULTS.RecvDgramRet.pucUserModeBuffer = pUserBufInfo->pucUserModeBuffer;
TSFreeMemory(pUserBufInfo);
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////
// private functions
/////////////////////////////////////////////////////////////
// ---------------------------------------------------------
//
// Function: TSReceiveBufferComplete
//
// Arguments: pDeviceObject -- device object that called protocol
// pIrp -- IRP used in the call
// pContext -- context used for the call
//
// Returns: status of operation (STATUS_MORE_PROCESSING_REQUIRED)
//
// Descript: Gets the result of the command, unlock the buffer,
// and does other necessary cleanup
//
// ---------------------------------------------------------
#pragma warning(disable: UNREFERENCED_PARAM)
TDI_STATUS
TSReceiveBufferComplete(PDEVICE_OBJECT pDeviceObject,
PIRP pLowerIrp,
PVOID pvContext)
{
PUSERBUF_INFO pUserBufInfo = (PUSERBUF_INFO)pvContext;
NTSTATUS lStatus = pLowerIrp->IoStatus.Status;
ULONG ulBytesReceived = (ULONG)pLowerIrp->IoStatus.Information;
if (NT_SUCCESS(lStatus))
{
if (ulDebugLevel & ulDebugShowCommand)
{
DebugPrint2("%s: BytesReceived = 0x%08x\n",
strFuncP1,
ulBytesReceived);
}
pUserBufInfo->ulBytesTransferred = ulBytesReceived;
}
else
{
if (ulDebugLevel & ulDebugShowCommand)
{
DebugPrint2("%s: Completed with status 0x%08x\n",
strFuncP1,
lStatus);
}
}
//
// now cleanup
//
TSFreeUserBuffer(pUserBufInfo->pLowerMdl);
if (pUserBufInfo->pReturnTdiConnectInfo)
{
TSFreeMemory(pUserBufInfo->pReturnTdiConnectInfo);
}
if (pUserBufInfo->pReceiveTdiConnectInfo)
{
TSFreeMemory(pUserBufInfo->pReceiveTdiConnectInfo);
}
TSSetEvent(&pUserBufInfo->TdiEventCompleted);
TSFreeIrp(pLowerIrp, NULL);
pUserBufInfo->pLowerIrp = NULL;
return TDI_MORE_PROCESSING;
}
#pragma warning(default: UNREFERENCED_PARAM)
///////////////////////////////////////////////////////////////////////////////
// end of file buffer.cpp
///////////////////////////////////////////////////////////////////////////////