///////////////////////////////////////////////////////// // // 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 ///////////////////////////////////////////////////////////////////////////////