|
|
/////////////////////////////////////////////////////////
//
// Copyright (c) 2001 Microsoft Corporation
//
// Module Name:
// receive
//
// Abstract:
// This module contains code which deals with receiving data
//
//////////////////////////////////////////////////////////
#include "sysvars.h"
//////////////////////////////////////////////////////////////
// private constants, types, and prototypes
//////////////////////////////////////////////////////////////
const PCHAR strFunc1 = "TSReceive"; const PCHAR strFunc2 = "TSReceiveHandler"; const PCHAR strFunc3 = "TSRcvExpeditedHandler"; const PCHAR strFunc4 = "TSChainedReceiveHandler"; const PCHAR strFunc5 = "TSChainedRcvExpeditedHandler"; const PCHAR strFuncP1 = "TSReceiveComplete"; const PCHAR strFuncP2 = "TSShowReceiveInfo"; const PCHAR strFuncP3 = "TSGetRestOfData"; const PCHAR strFuncP4 = "TSCommonReceive"; const PCHAR strFuncP5 = "TSCommonChainedReceive";
//
// completion context
//
struct RECEIVE_CONTEXT { PMDL pLowerMdl; // mdl from lower irp
PRECEIVE_DATA pReceiveData; // above structure
PADDRESS_OBJECT pAddressObject; BOOLEAN fIsExpedited; }; typedef RECEIVE_CONTEXT *PRECEIVE_CONTEXT;
//
// completion function
//
TDI_STATUS TSReceiveComplete( PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context );
PIRP TSGetRestOfData( PADDRESS_OBJECT pAddressObject, PRECEIVE_DATA pReceiveData, BOOLEAN fIsExpedited );
VOID TSShowReceiveInfo( PADDRESS_OBJECT pAddressObject, CONNECTION_CONTEXT ConnectionContext, ULONG ulReceiveFlags, ULONG ulBytesIndicated, ULONG ulBytesAvailable, PVOID pvTsdu, BOOLEAN fIsChained );
TDI_STATUS TSCommonReceive( PADDRESS_OBJECT pAddressObject, ULONG ulBytesTotal, ULONG ulBytesIndicated, ULONG ulReceiveFlags, PVOID pvTsdu, BOOLEAN fIsExpedited, PULONG pulBytesTaken, PIRP *pIoRequestPacket );
TDI_STATUS TSCommonChainedReceive( PADDRESS_OBJECT pAddressObject, ULONG ulReceiveLength, ULONG ulStartingOffset, PMDL pReceiveMdl, BOOLEAN fIsExpedited, PVOID pvTsduDescriptor );
//////////////////////////////////////////////////////////////
// public functions
//////////////////////////////////////////////////////////////
// -----------------------------------------------------------------
//
// Function: TSReceive
//
// Arguments: pEndpointObject -- current endpoint
// pIrp -- completion information
//
// Returns: NTSTATUS (normally pending)
//
// Descript: This function receives data over a connection
//
// ----------------------------------------------------------------------------
NTSTATUS TSReceive(PENDPOINT_OBJECT pEndpoint, PSEND_BUFFER pSendBuffer, PRECEIVE_BUFFER pReceiveBuffer) { PADDRESS_OBJECT pAddressObject = pEndpoint->pAddressObject;
//
// assume no packet
//
pReceiveBuffer->RESULTS.RecvDgramRet.ulBufferLength = 0;
if (pAddressObject) { PRECEIVE_DATA pReceiveData;
//
// just get the first packet from the queue
// check expedited list First
//
TSAcquireSpinLock(&pAddressObject->TdiSpinLock); pReceiveData = pAddressObject->pHeadRcvExpData; if (pReceiveData) { //
// fix up the lists as necessary
//
if (pReceiveData->pNextReceiveData) { pReceiveData->pNextReceiveData->pPrevReceiveData = NULL; } else { pAddressObject->pTailRcvExpData = NULL; } pAddressObject->pHeadRcvExpData = pReceiveData->pNextReceiveData; }
//
// if no expedited receives, check normal list
//
else { pReceiveData = pAddressObject->pHeadReceiveData; if (pReceiveData) { //
// fix up the lists as necessary
//
if (pReceiveData->pNextReceiveData) { pReceiveData->pNextReceiveData->pPrevReceiveData = NULL; } else { pAddressObject->pTailReceiveData = NULL; } pAddressObject->pHeadReceiveData = pReceiveData->pNextReceiveData; } } TSReleaseSpinLock(&pAddressObject->TdiSpinLock); //
// if we got a packet to return, then lets return it..
// and release its memory
//
if (pReceiveData) { //
// show debug, if it is turned on, and only if we actually
// are returning a packet
//
if (ulDebugLevel & ulDebugShowCommand) { DebugPrint1("\nCommand = ulRECEIVE\n" "FileObject = %p\n", pEndpoint); } if (pReceiveData->ulBufferLength > pSendBuffer->COMMAND_ARGS.SendArgs.ulBufferLength) { pReceiveData->ulBufferLength = pSendBuffer->COMMAND_ARGS.SendArgs.ulBufferLength; } //
// attempt to lock down the memory
//
PMDL pMdl = TSMakeMdlForUserBuffer(pSendBuffer->COMMAND_ARGS.SendArgs.pucUserModeBuffer, pReceiveData->ulBufferLength, IoModifyAccess); if (pMdl) { RtlCopyMemory(MmGetSystemAddressForMdl(pMdl), pReceiveData->pucDataBuffer, pReceiveData->ulBufferLength); TSFreeUserBuffer(pMdl); } else { pReceiveData->ulBufferLength = 0; } pReceiveBuffer->RESULTS.RecvDgramRet.ulBufferLength = pReceiveData->ulBufferLength;
TSFreeMemory(pReceiveData->pucDataBuffer); TSFreeMemory(pReceiveData); } }
return STATUS_SUCCESS; }
// -----------------------------------------------
//
// Function: TSReceiveHandler
//
// Arguments: pvTdiEventContext -- really pointer to our AddressObject
// Connection_Context -- really pointer to our Endpoint
// ReceiveFlags -- nature of received data
// ulBytesIndicated --- length of data in buffer
// ulBytesTotal -- total length of datagram
// pulBytesTaken -- stuff with bytes used by this driver
// pvTsdu -- data buffer
// pIoRequestPacket -- pIrp in case not all data received
//
// Returns: STATUS_DATA_NOT_ACCEPTED (we didn't want data)
// STATUS_SUCCESS (we used all data & are done with it)
// STATUS_MORE_PROCESSING_REQUIRED -- we supplied an IRP for rest
//
// Descript: Event handler for incoming receives on connection
//
// -----------------------------------------------
TDI_STATUS TSReceiveHandler(PVOID pvTdiEventContext, CONNECTION_CONTEXT ConnectionContext, ULONG ulReceiveFlags, ULONG ulBytesIndicated, ULONG ulBytesTotal, PULONG pulBytesTaken, PVOID pvTsdu, PIRP *ppIoRequestPacket)
{ PADDRESS_OBJECT pAddressObject = (PADDRESS_OBJECT)pvTdiEventContext;
if (ulDebugLevel & ulDebugShowHandlers) { DebugPrint1("\n >>>> %s\n", strFunc2); TSShowReceiveInfo(pAddressObject, ConnectionContext, ulReceiveFlags, ulBytesIndicated, ulBytesTotal, pvTsdu, FALSE); }
return TSCommonReceive(pAddressObject, ulBytesTotal, ulBytesIndicated, ulReceiveFlags, pvTsdu, ((ulReceiveFlags & TDI_RECEIVE_EXPEDITED) != 0), pulBytesTaken, ppIoRequestPacket); }
// -----------------------------------------------
//
// Function: TSRcvExpeditedHandler
//
// Arguments: pvTdiEventContext -- really pointer to our AddressObject
// Connection_Context -- really pointer to our Endpoint
// ReceiveFlags -- nature of received data
// ulBytesIndicated --- length of data in buffer
// ulBytesTotal -- total length of datagram
// pulBytesTaken -- stuff with bytes used by this driver
// pvTsdu -- data buffer
// pIoRequestPacket -- pIrp in case not all data received
//
// Returns: STATUS_DATA_NOT_ACCEPTED (we didn't want data)
// STATUS_SUCCESS (we used all data & are done with it)
// STATUS_MORE_PROCESSING_REQUIRED -- we supplied an IRP for rest
//
// Descript: Event handler for incoming expedited receives on connection
//
// -----------------------------------------------
TDI_STATUS TSRcvExpeditedHandler(PVOID pvTdiEventContext, CONNECTION_CONTEXT ConnectionContext, ULONG ulReceiveFlags, ULONG ulBytesIndicated, ULONG ulBytesTotal, PULONG pulBytesTaken, PVOID pvTsdu, PIRP *ppIoRequestPacket)
{ PADDRESS_OBJECT pAddressObject = (PADDRESS_OBJECT)pvTdiEventContext;
if (ulDebugLevel & ulDebugShowHandlers) { DebugPrint1("\n >>>> %s\n", strFunc3); TSShowReceiveInfo(pAddressObject, ConnectionContext, ulReceiveFlags, ulBytesIndicated, ulBytesTotal, pvTsdu, FALSE); } return TSCommonReceive(pAddressObject, ulBytesTotal, ulBytesIndicated, ulReceiveFlags, pvTsdu, TRUE, pulBytesTaken, ppIoRequestPacket); }
// -----------------------------------------------
//
// Function: TSChainedReceiveHandler
//
// Arguments: pvTdiEventContext -- really pointer to our AddressObject
// Connection_Context -- really pointer to our Endpoint
// ReceiveFlags -- nature of received data
// ulReceiveLength --- length of data in buffer
// ulStartingOffset -- total length of datagram
// pReceiveMdl -- data buffer
// pTsduDescriptor -- returns value for TdiReturnChainedReceives
//
// Returns: STATUS_DATA_NOT_ACCEPTED (we didn't want data)
// STATUS_SUCCESS (we used all data & are done with it)
// STATUS_MORE_PROCESSING_REQUIRED -- we supplied an IRP for rest
//
// Descript: Event handler for incoming receives on connection
//
// -----------------------------------------------
TDI_STATUS TSChainedReceiveHandler(PVOID pvTdiEventContext, CONNECTION_CONTEXT ConnectionContext, ULONG ulReceiveFlags, ULONG ulReceiveLength, ULONG ulStartingOffset, PMDL pReceiveMdl, PVOID pvTsduDescriptor) { PADDRESS_OBJECT pAddressObject = (PADDRESS_OBJECT)pvTdiEventContext; if (ulDebugLevel & ulDebugShowHandlers) { DebugPrint1("\n >>>> %s\n", strFunc4); TSShowReceiveInfo(pAddressObject, ConnectionContext, ulReceiveFlags, ulReceiveLength, ulStartingOffset, pReceiveMdl, TRUE); }
return TSCommonChainedReceive(pAddressObject, ulReceiveLength, ulStartingOffset, pReceiveMdl, ((ulReceiveFlags & TDI_RECEIVE_EXPEDITED) != 0), pvTsduDescriptor); }
// -----------------------------------------------
//
// Function: TSChainedRcvExpeditedHandler
//
// Arguments: pvTdiEventContext -- really pointer to our AddressObject
// Connection_Context -- really pointer to our Endpoint
// ReceiveFlags -- nature of received data
// ulReceiveLength --- length of data in buffer
// ulStartingOffset -- total length of datagram
// pReceiveMdl -- data buffer
// pTsduDescriptor -- returns value for TdiReturnChainedReceives
//
// Returns: STATUS_DATA_NOT_ACCEPTED (we didn't want data)
// STATUS_SUCCESS (we used all data & are done with it)
// STATUS_MORE_PROCESSING_REQUIRED -- we supplied an IRP for rest
//
// Descript: Event handler for incoming receives on connection
//
// -----------------------------------------------
TDI_STATUS TSChainedRcvExpeditedHandler(PVOID pvTdiEventContext, CONNECTION_CONTEXT ConnectionContext, ULONG ulReceiveFlags, ULONG ulReceiveLength, ULONG ulStartingOffset, PMDL pReceiveMdl, PVOID pvTsduDescriptor) { PADDRESS_OBJECT pAddressObject = (PADDRESS_OBJECT)pvTdiEventContext;
if (ulDebugLevel & ulDebugShowHandlers) { DebugPrint1("\n >>>> %s\n", strFunc5); TSShowReceiveInfo(pAddressObject, ConnectionContext, ulReceiveFlags, ulReceiveLength, ulStartingOffset, pReceiveMdl, TRUE); }
return TSCommonChainedReceive(pAddressObject, ulReceiveLength, ulStartingOffset, pReceiveMdl, TRUE, pvTsduDescriptor); }
/////////////////////////////////////////////////////////////
// private functions
/////////////////////////////////////////////////////////////
// ---------------------------------------------------------
//
// Function: TSReceiveComplete
//
// Arguments: pDeviceObject -- device object that called Receive/Datagram
// 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 receive, stuffs result into
// receive buffer, completes the IRP from the dll, and
// cleans up the Irp and associated data from the receive
//
// ---------------------------------------------------------
#pragma warning(disable: UNREFERENCED_PARAM)
TDI_STATUS TSReceiveComplete(PDEVICE_OBJECT pDeviceObject, PIRP pLowerIrp, PVOID pvContext)
{ PRECEIVE_CONTEXT pReceiveContext = (PRECEIVE_CONTEXT)pvContext; NTSTATUS lStatus = pLowerIrp->IoStatus.Status; ULONG ulBytesCopied = (ULONG)pLowerIrp->IoStatus.Information; PADDRESS_OBJECT pAddressObject = pReceiveContext->pAddressObject; PRECEIVE_DATA pReceiveData = pReceiveContext->pReceiveData;
if (NT_SUCCESS(lStatus)) { if (ulDebugLevel & ulDebugShowCommand) { DebugPrint2("%s: %u BytesCopied\n", strFuncP1, ulBytesCopied); } pReceiveData->ulBufferUsed += ulBytesCopied; if (pReceiveData->ulBufferUsed >= pReceiveData->ulBufferLength) { TSPacketReceived(pAddressObject, pReceiveData, pReceiveContext->fIsExpedited); } else { DebugPrint1("%s: Data Incomplete\n", strFuncP1); TSFreeMemory(pReceiveData->pucDataBuffer); TSFreeMemory(pReceiveData); } } else { DebugPrint2("%s: Completed with status 0x%08x\n", strFuncP1, lStatus); TSFreeMemory(pReceiveData->pucDataBuffer); TSFreeMemory(pReceiveData); }
//
// now cleanup
//
TSFreeIrp(pLowerIrp, pAddressObject->pIrpPool); TSFreeBuffer(pReceiveContext->pLowerMdl);
TSFreeMemory(pReceiveContext);
return TDI_MORE_PROCESSING; }
#pragma warning(default: UNREFERENCED_PARAM)
// ---------------------------------
//
// Function: TSShowReceiveInfo
//
// Arguments: pAddressObject -- the address object associated with this endpoint
// ConnectionContext -- endpoint of this connection
// ulReceiveFlags -- info about the receive
// ulBytesIndicated -- bytes indicated up
// ulBytesAvailable -- total bytes (or starting offset)
// pvTsdu -- ptr to the data (or to its mdl)
// fIsChained -- if TRUE, then this is chained receive
//
// Returns: none
//
// Descript: shows info passed to receive handler
//
// --------------------------------
VOID TSShowReceiveInfo(PADDRESS_OBJECT pAddressObject, CONNECTION_CONTEXT ConnectionContext, ULONG ulReceiveFlags, ULONG ulBytesIndicated, ULONG ulBytesAvailable, PVOID pvTsdu, BOOLEAN fIsChained) { DebugPrint3("pAddressObject = %p\n" "pEndpoint = %p\n" "ulReceiveFlags = 0x%08x\n", pAddressObject, ConnectionContext, ulReceiveFlags);
if (ulReceiveFlags & TDI_RECEIVE_NORMAL) { DebugPrint0(" TDI_RECEIVE_NORMAL\n"); } if (ulReceiveFlags & TDI_RECEIVE_EXPEDITED) { DebugPrint0(" TDI_RECEIVE_EXPEDITED\n"); } if (ulReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE) { DebugPrint0(" TDI_RECEIVE_ENTIRE_MESSAGE\n"); } if (ulReceiveFlags & TDI_RECEIVE_AT_DISPATCH_LEVEL) { DebugPrint0(" TDI_RECEIVE_AT_DISPATCH_LEVEL\n"); } if (fIsChained) { DebugPrint3("ReceiveLength = %u\n" "StartingOffset = 0x%08x\n" "pMdl = %p\n", ulBytesIndicated, ulBytesAvailable, pvTsdu); } else { DebugPrint3("BytesIndicated = %u\n" "TotalBytes = %u\n" "pDataBuffer = %p\n", ulBytesIndicated, ulBytesAvailable, pvTsdu); } }
// ------------------------------------------------------
//
// Function: TSGetRestOfData
//
// Arguments: pAddressObject -- address object we are receiving on
// pReceiveData -- what we have received so far..
//
// Returns: Irp to return to transport, to get rest of data (NULL if error)
//
// Descript: This function sets up the IRP to get the rest of a datagram
// that was only partially delivered via the event handler
//
// -------------------------------------------------
PIRP TSGetRestOfData(PADDRESS_OBJECT pAddressObject, PRECEIVE_DATA pReceiveData, BOOLEAN fIsExpedited)
{ PUCHAR pucDataBuffer = pReceiveData->pucDataBuffer + pReceiveData->ulBufferUsed; ULONG ulBufferLength = pReceiveData->ulBufferLength - pReceiveData->ulBufferUsed; PRECEIVE_CONTEXT pReceiveContext = NULL; PMDL pReceiveMdl = NULL;
//
// allocate all the necessary structures
// our context
//
if ((TSAllocateMemory((PVOID *)&pReceiveContext, sizeof(RECEIVE_CONTEXT), strFuncP3, "ReceiveContext")) != STATUS_SUCCESS) { goto cleanup; }
//
// then the actual mdl
//
pReceiveMdl = TSAllocateBuffer(pucDataBuffer, ulBufferLength);
if (pReceiveMdl) { //
// set up the completion context
//
pReceiveContext->pLowerMdl = pReceiveMdl; pReceiveContext->pReceiveData = pReceiveData; pReceiveContext->pAddressObject = pAddressObject; pReceiveContext->fIsExpedited = fIsExpedited;
//
// finally, the irp itself
//
PIRP pLowerIrp = TSAllocateIrp(pAddressObject->pEndpoint->GenHead.pDeviceObject, pAddressObject->pIrpPool);
if (pLowerIrp) { //
// if made it to here, everything is correctly allocated
// set up the irp for the call
//
#pragma warning(disable: CONSTANT_CONDITIONAL)
TdiBuildReceive(pLowerIrp, pAddressObject->pEndpoint->GenHead.pDeviceObject, pAddressObject->pEndpoint->GenHead.pFileObject, TSReceiveComplete, pReceiveContext, pReceiveMdl, TDI_RECEIVE_NORMAL, ulBufferLength);
#pragma warning(default: CONSTANT_CONDITIONAL)
return pLowerIrp; } }
//
// get here if there was an allocation failure
// need to clean up everything else...
//
cleanup: if (pReceiveContext) { TSFreeMemory(pReceiveContext); } if (pReceiveMdl) { TSFreeBuffer(pReceiveMdl); } return NULL; }
// ---------------------------------------------
//
// Function: TSCommonReceive
//
// Arguments: see TSReceiveHandler
//
// Returns: status to return to protocol
//
// Descript: Common code for TSReceiveHandler and
// TSRcvExpeditedHandler. Pretty much all the work is
// done here
//
// ---------------------------------------------
TDI_STATUS TSCommonReceive(PADDRESS_OBJECT pAddressObject, ULONG ulBytesTotal, ULONG ulBytesIndicated, ULONG ulReceiveFlags, PVOID pvTsdu, BOOLEAN fIsExpedited, PULONG pulBytesTaken, PIRP *pIoRequestPacket) { //
// check for a bad condition -- more bytes indicated that total
//
if (ulBytesIndicated > ulBytesTotal) { DebugPrint2("%u bytes indicated > %u bytes total\n", ulBytesIndicated, ulBytesTotal); return TDI_NOT_ACCEPTED; }
PRECEIVE_DATA pReceiveData;
if ( (TSAllocateMemory((PVOID *)&pReceiveData, sizeof(RECEIVE_DATA), strFuncP4, "ReceiveData")) == STATUS_SUCCESS) { PUCHAR pucDataBuffer = NULL; if ((TSAllocateMemory((PVOID *)&pucDataBuffer, ulBytesTotal, strFuncP4, "DataBuffer")) == STATUS_SUCCESS) { pReceiveData->pucDataBuffer = pucDataBuffer; pReceiveData->ulBufferLength = ulBytesTotal; } else { TSFreeMemory(pReceiveData); return TDI_NOT_ACCEPTED; } } else { return TDI_NOT_ACCEPTED; }
//
// copy the data indicated to us into the buffer
//
TdiCopyLookaheadData(pReceiveData->pucDataBuffer, pvTsdu, ulBytesIndicated, ulReceiveFlags); pReceiveData->ulBufferUsed = ulBytesIndicated;
//
// first case -- entire packet indicated to us
//
if (ulBytesIndicated == ulBytesTotal) { TSPacketReceived(pAddressObject, pReceiveData, fIsExpedited);
*pulBytesTaken = ulBytesTotal; *pIoRequestPacket = NULL; return TDI_SUCCESS; }
//
// second case -- only part of data indicated up
//
else { PIRP pLowerIrp = TSGetRestOfData(pAddressObject, pReceiveData, fIsExpedited);
if (pLowerIrp) { //
// need to do this since we are bypassing IoCallDriver
//
IoSetNextIrpStackLocation(pLowerIrp); *pulBytesTaken = ulBytesIndicated; *pIoRequestPacket = pLowerIrp; return TDI_MORE_PROCESSING; } else { DebugPrint1("%s: unable to get rest of packet\n", strFuncP4); TSFreeMemory(pReceiveData->pucDataBuffer); TSFreeMemory(pReceiveData); return TDI_NOT_ACCEPTED; } } }
// ---------------------------------------------
//
// Function: TSCommonChainedReceive
//
// Arguments: see TStChainedRcvhandler
//
// Returns: status
//
// Descript: Common code for TSChainedReceiveHandler and
// TSChainedRcvExpeditedHandler. Pretty much all the work is
// done here
//
// ---------------------------------------------
TDI_STATUS TSCommonChainedReceive(PADDRESS_OBJECT pAddressObject, ULONG ulReceiveLength, ULONG ulStartingOffset, PMDL pReceiveMdl, BOOLEAN fIsExpedited, PVOID pvTsduDescriptor) { PRECEIVE_DATA pReceiveData;
if ((TSAllocateMemory((PVOID *)&pReceiveData, sizeof(RECEIVE_DATA), strFuncP5, "ReceiveData")) == STATUS_SUCCESS) { PUCHAR pucDataBuffer; if((TSAllocateMemory((PVOID *)&pucDataBuffer, ulReceiveLength, strFuncP5, "DataBuffer")) == STATUS_SUCCESS) { ULONG ulBytesCopied;
TdiCopyMdlToBuffer(pReceiveMdl, ulStartingOffset, pucDataBuffer, 0, ulReceiveLength, &ulBytesCopied);
//
// if successfully copied all data
//
if (ulBytesCopied == ulReceiveLength) { pReceiveData->pucDataBuffer = pucDataBuffer; pReceiveData->ulBufferLength = ulReceiveLength; pReceiveData->ulBufferUsed = ulReceiveLength; TSPacketReceived(pAddressObject, pReceiveData, fIsExpedited);
return TDI_SUCCESS; }
//
// error in copying data!
//
else { DebugPrint1("%s: error copying data\n", strFuncP5); TSFreeMemory(pucDataBuffer); TSFreeMemory(pReceiveData); } } else // unable to allocate pucDataBuffer
{ TSFreeMemory(pReceiveData); } } return TDI_NOT_ACCEPTED; }
///////////////////////////////////////////////////////////////////////////////
// end of file receive.cpp
///////////////////////////////////////////////////////////////////////////////
|