///////////////////////////////////////////////////////// // // Copyright (c) 2001 Microsoft Corporation // // Module Name: // rcvdgram // // Abstract: // This module contains code which deals with receiving datagrams // ////////////////////////////////////////////////////////// #include "sysvars.h" ////////////////////////////////////////////////////////////// // private constants, types, and prototypes ////////////////////////////////////////////////////////////// const PCHAR strFunc1 = "TSReceiveDatagram"; const PCHAR strFunc2 = "TSRcvDatagramHandler"; const PCHAR strFunc3 = "TSChainedRcvDatagramHandler"; const PCHAR strFuncP1 = "TSReceiveDgramComplete"; const PCHAR strFuncP2 = "TSGetRestOfDgram"; const PCHAR strFuncP3 = "TSShowDgramInfo"; // // completion information structure // struct RECEIVE_CONTEXT { PMDL pLowerMdl; // mdl from lower irp PRECEIVE_DATA pReceiveData; // above structure PADDRESS_OBJECT pAddressObject; // associate address object PIRP_POOL pIrpPool; }; typedef RECEIVE_CONTEXT *PRECEIVE_CONTEXT; // // completion function // TDI_STATUS TSReceiveDgramComplete( PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context ); PIRP TSGetRestOfDgram( PADDRESS_OBJECT pAddressObject, PRECEIVE_DATA pReceiveData ); VOID TSShowDgramInfo( PVOID pvTdiEventContext, LONG lSourceAddressLength, PVOID pvSourceAddress, LONG lOptionsLength, PVOID pvOptions, ULONG ulReceiveDatagramFlags ); ////////////////////////////////////////////////////////////// // public functions ////////////////////////////////////////////////////////////// // ----------------------------------------------------------------- // // Function: TSReceiveDatagram // // Arguments: pAddressObject -- address object // pSendBuffer -- arguments from user dll // pIrp -- completion information // // Returns: STATUS_SUCCESS // // Descript: This function checks to see if a datagram has been received // on this address object. If so, and if it matches certain // criteria, it returns it. Otherwise it returns with no data. // // ---------------------------------------------------------------------------- NTSTATUS TSReceiveDatagram(PADDRESS_OBJECT pAddressObject, PSEND_BUFFER pSendBuffer, PRECEIVE_BUFFER pReceiveBuffer) { PTRANSPORT_ADDRESS pTransportAddress = (PTRANSPORT_ADDRESS)&pSendBuffer->COMMAND_ARGS.SendArgs.TransAddr; BOOLEAN fMatchAddress = (BOOLEAN)(pTransportAddress->TAAddressCount > 0); PRECEIVE_DATA pReceiveData = NULL; // // if need to match to address, return the first packet in the queue // that was sent from the specified address. // if (fMatchAddress) { ULONG ulCompareLength = FIELD_OFFSET(TRANSPORT_ADDRESS, Address) + FIELD_OFFSET(TA_ADDRESS, Address) + pTransportAddress->Address[0].AddressLength; if (pTransportAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IP) { ulCompareLength -= 8; // ignore sin_zero[8] } TSAcquireSpinLock(&pAddressObject->TdiSpinLock); pReceiveData = pAddressObject->pHeadReceiveData; while(pReceiveData) { if (RtlEqualMemory(pTransportAddress, &pReceiveData->TransAddr, ulCompareLength)) { break; } pReceiveData = pReceiveData->pNextReceiveData; } // // did we find anything? // if (pReceiveData) { // // fix up the lists as necessary // if (pReceiveData->pPrevReceiveData) { pReceiveData->pPrevReceiveData->pNextReceiveData = pReceiveData->pNextReceiveData; } else { pAddressObject->pHeadReceiveData = pReceiveData->pNextReceiveData; } if (pReceiveData->pNextReceiveData) { pReceiveData->pNextReceiveData->pPrevReceiveData = pReceiveData->pPrevReceiveData; } else { pAddressObject->pTailReceiveData = pReceiveData->pPrevReceiveData; } } TSReleaseSpinLock(&pAddressObject->TdiSpinLock); } // // if not matching address, just get the first packet from the queue // else { TSAcquireSpinLock(&pAddressObject->TdiSpinLock); 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) { // // we are only showing debug if we actually return a packet // if (ulDebugLevel & ulDebugShowCommand) { DebugPrint1("\nCommand = ulRECEIVEDATAGRAM\n" "FileObject = %p\n", pAddressObject); if (pTransportAddress->TAAddressCount) { TSPrintTaAddress(pTransportAddress->Address); } } 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(&pReceiveBuffer->RESULTS.RecvDgramRet.TransAddr, &pReceiveData->TransAddr, sizeof(TRANSADDR)); RtlCopyMemory(MmGetSystemAddressForMdl(pMdl), pReceiveData->pucDataBuffer, pReceiveData->ulBufferLength); TSFreeUserBuffer(pMdl); } else { pReceiveData->ulBufferLength = 0; } pReceiveBuffer->RESULTS.RecvDgramRet.ulBufferLength = pReceiveData->ulBufferLength; TSFreeMemory(pReceiveData->pucDataBuffer); TSFreeMemory(pReceiveData); } else { pReceiveBuffer->RESULTS.RecvDgramRet.ulBufferLength = 0; } return STATUS_SUCCESS; } // ----------------------------------------------- // // Function: TSRcvDatagramHandler // // Arguments: pvTdiEventContext -- really pointer to our AddressObject // lSourceAddressLength -- #bytes of source address // pvSourceAddress -- TransportAddress // lOptionsLength -- #bytes of transport-specific options // pvOptions -- options string // ulReceiveDatagramFlags -- nature of datagram received // 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 datagrams // // ----------------------------------------------- TDI_STATUS TSRcvDatagramHandler(PVOID pvTdiEventContext, LONG lSourceAddressLength, PVOID pvSourceAddress, LONG lOptionsLength, PVOID pvOptions, ULONG ulReceiveDatagramFlags, ULONG ulBytesIndicated, ULONG ulBytesTotal, PULONG pulBytesTaken, PVOID pvTsdu, PIRP *pIoRequestPacket) { // // show debug information // if (ulDebugLevel & ulDebugShowHandlers) { DebugPrint1("\n >>>> %s\n", strFunc2); TSShowDgramInfo(pvTdiEventContext, lSourceAddressLength, pvSourceAddress, lOptionsLength, pvOptions, ulReceiveDatagramFlags); DebugPrint3("BytesIndicated = %u\n" "BytesTotal = %u\n" "pTSDU = %p\n", ulBytesIndicated, ulBytesTotal, pvTsdu); } // // bad situation if more bytes are indicated than the total in the packet // if (ulBytesIndicated > ulBytesTotal) { DebugPrint2("%d bytes indicated > %u bytes total\n", ulBytesIndicated, ulBytesTotal); } // // now start doing the work... // PADDRESS_OBJECT pAddressObject = (PADDRESS_OBJECT)pvTdiEventContext; PRECEIVE_DATA pReceiveData; TDI_STATUS TdiStatus = TDI_SUCCESS; // default -- we are done with packet // (also returned in case of error) if ((TSAllocateMemory((PVOID *)&pReceiveData, sizeof(RECEIVE_DATA), strFunc2, "ReceiveData")) == STATUS_SUCCESS) { PUCHAR pucDataBuffer = NULL; if ((TSAllocateMemory((PVOID *)&pucDataBuffer, ulBytesTotal, strFunc2, "DataBuffer")) == STATUS_SUCCESS) { RtlCopyMemory(&pReceiveData->TransAddr, pvSourceAddress, lSourceAddressLength); pReceiveData->pucDataBuffer = pucDataBuffer; pReceiveData->ulBufferLength = ulBytesTotal; TdiCopyLookaheadData(pucDataBuffer, pvTsdu, ulBytesIndicated, ulReceiveDatagramFlags); pReceiveData->ulBufferUsed = ulBytesIndicated; if (ulBytesIndicated == ulBytesTotal) // note: should never be > { TSPacketReceived(pAddressObject, pReceiveData, FALSE); *pulBytesTaken = ulBytesTotal; *pIoRequestPacket = NULL; } else // not all data is present!! { PIRP pLowerIrp = TSGetRestOfDgram(pAddressObject, pReceiveData); if (pLowerIrp) { // // need to do this since we are bypassing IoCallDriver // IoSetNextIrpStackLocation(pLowerIrp); *pulBytesTaken = ulBytesIndicated; *pIoRequestPacket = pLowerIrp; TdiStatus = TDI_MORE_PROCESSING; } else { TSFreeMemory(pReceiveData->pucDataBuffer); TSFreeMemory(pReceiveData); } } } else // unable to allocate pucDataBuffer { TSFreeMemory(pReceiveData); } } return TdiStatus; } // ---------------------------------------------- // // Function: TSChainedRcvDatagramHandler // // Arguments: pvTdiEventContext -- really pointer to our AddressObject // lSourceAddressLength -- #bytes of source address // pvSourceAddress -- TransportAddress // lOptionsLength -- #bytes of transport-specific options // pvOptions -- options string // ulReceiveDatagramFlags -- nature of datagram received // ulReceiveDatagramLength -- bytes in received datagram // ulStartingOffset -- starting offset of data within MDL // pTsdu -- data buffer (as an mdl) // pvTsduDescriptor -- handle to use when completing if pend // // Returns: STATUS_DATA_NOT_ACCEPTED or STATUS_SUCCESS // // Descript: Deals with receiving chained datagrams (where the // entire datagram is always available) // // ----------------------------------------------- #pragma warning(disable: UNREFERENCED_PARAM) TDI_STATUS TSChainedRcvDatagramHandler(PVOID pvTdiEventContext, LONG lSourceAddressLength, PVOID pvSourceAddress, LONG lOptionsLength, PVOID pvOptions, ULONG ulReceiveDatagramFlags, ULONG ulReceiveDatagramLength, ULONG ulStartingOffset, PMDL pMdl, PVOID pvTsduDescriptor) { if (ulDebugLevel & ulDebugShowHandlers) { DebugPrint1("\n >>>> %s\n", strFunc3); TSShowDgramInfo(pvTdiEventContext, lSourceAddressLength, pvSourceAddress, lOptionsLength, pvOptions, ulReceiveDatagramFlags); DebugPrint3("DataLength = %u\n" "StartingOffset = %u\n" "pTSDU = %p\n", ulReceiveDatagramLength, ulStartingOffset, pMdl); } // // now do the work.. // PRECEIVE_DATA pReceiveData; PADDRESS_OBJECT pAddressObject = (PADDRESS_OBJECT)pvTdiEventContext; if ((TSAllocateMemory((PVOID *)&pReceiveData, sizeof(RECEIVE_DATA), strFunc3, "ReceiveData")) == STATUS_SUCCESS) { PUCHAR pucDataBuffer = NULL; if ((TSAllocateMemory((PVOID *)&pucDataBuffer, ulReceiveDatagramLength, strFunc3, "DataBuffer")) == STATUS_SUCCESS) { ULONG ulBytesCopied; RtlCopyMemory(&pReceiveData->TransAddr, pvSourceAddress, lSourceAddressLength); TdiCopyMdlToBuffer(pMdl, ulStartingOffset, pucDataBuffer, 0, ulReceiveDatagramLength, &ulBytesCopied); // // if successfully copied all data // if (ulBytesCopied == ulReceiveDatagramLength) { UCHAR ucFirstChar = *pucDataBuffer; pReceiveData->pucDataBuffer = pucDataBuffer; pReceiveData->ulBufferLength = ulReceiveDatagramLength; pReceiveData->ulBufferUsed = ulReceiveDatagramLength; TSPacketReceived(pAddressObject, pReceiveData, FALSE); } // // error in copying data! // else { DebugPrint1("%s: error copying data\n", strFunc3); TSFreeMemory(pucDataBuffer); TSFreeMemory(pReceiveData); } } else // unable to allocate pucDataBuffer { TSFreeMemory(pReceiveData); } } return TDI_SUCCESS; // we are done with packet } #pragma warning(default: UNREFERENCED_PARAM) ///////////////////////////////////////////////////////////// // private functions ///////////////////////////////////////////////////////////// // --------------------------------------------------------- // // Function: TSReceiveDgramComplete // // Arguments: pDeviceObject -- device object that called ReceiveDatagram // 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 and adds the packet // to the receive queue of the address object. Then // cleans up // // --------------------------------------------------------- #pragma warning(disable: UNREFERENCED_PARAM) TDI_STATUS TSReceiveDgramComplete(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, FALSE); } 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, pReceiveContext->pIrpPool); TSFreeBuffer(pReceiveContext->pLowerMdl); TSFreeMemory(pReceiveContext); return STATUS_MORE_PROCESSING_REQUIRED; } #pragma warning(default: UNREFERENCED_PARAM) // ------------------------------------------------------ // // Function: TSGetRestOfDgram // // 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 TSGetRestOfDgram(PADDRESS_OBJECT pAddressObject, PRECEIVE_DATA pReceiveData) { 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), strFuncP2, "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; // // finally, the irp itself // PIRP pLowerIrp = TSAllocateIrp(pAddressObject->GenHead.pDeviceObject, pAddressObject->pIrpPool); if (pLowerIrp) { pReceiveContext->pIrpPool = pAddressObject->pIrpPool; // // if made it to here, everything is correctly allocated // set up the irp for the call // #pragma warning(disable: CONSTANT_CONDITIONAL) TdiBuildReceiveDatagram(pLowerIrp, pAddressObject->GenHead.pDeviceObject, pAddressObject->GenHead.pFileObject, TSReceiveDgramComplete, pReceiveContext, pReceiveMdl, 0, /// ulBufferLength, // 0 doesn't work with ipx NULL, NULL, TDI_RECEIVE_NORMAL); #pragma warning(default: CONSTANT_CONDITIONAL) // // mark it pending before returning control to transport // 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: TSShowDgramInfo // // Arguments: pvTdiEventContext -- really pointer to our AddressObject // lSourceAddressLength -- #bytes of source address // pvSourceAddress -- TransportAddress // lOptionsLength -- #bytes of transport-specific options // pvOptions -- options string // ulReceiveDatagramFlags -- nature of datagram received // // Returns: none // // Descript: shows info passed to the dgram handlers // // -------------------------------- VOID TSShowDgramInfo(PVOID pvTdiEventContext, LONG lSourceAddressLength, PVOID pvSourceAddress, LONG lOptionsLength, PVOID pvOptions, ULONG ulReceiveDatagramFlags) { DebugPrint2("pAddressObject = %p\n" "SourceAddressLength = %d\n", pvTdiEventContext, lSourceAddressLength); if (lSourceAddressLength) { PTRANSPORT_ADDRESS pTransportAddress = (PTRANSPORT_ADDRESS)pvSourceAddress; DebugPrint0("SourceAddress: "); TSPrintTaAddress(&pTransportAddress->Address[0]); } DebugPrint1("OptionsLength = %d\n", lOptionsLength); if (lOptionsLength) { PUCHAR pucTemp = (PUCHAR)pvOptions; DebugPrint0("Options: "); for (LONG lCount = 0; lCount < lOptionsLength; lCount++) { DebugPrint1("%02x ", *pucTemp); ++pucTemp; } DebugPrint0("\n"); } DebugPrint1("ReceiveDatagramFlags: 0x%08x\n", ulReceiveDatagramFlags); if (ulReceiveDatagramFlags & TDI_RECEIVE_BROADCAST) { DebugPrint0("TDI_RECEIVE_BROADCAST\n"); } if (ulReceiveDatagramFlags & TDI_RECEIVE_MULTICAST) { DebugPrint0("TDI_RECEIVE_MULTICAST\n"); } if (ulReceiveDatagramFlags & TDI_RECEIVE_PARTIAL) { DebugPrint0("TDI_RECEIVE_PARTIAL (legacy)\n"); } if (ulReceiveDatagramFlags & TDI_RECEIVE_NORMAL) // shouldn't see for datagram { DebugPrint0("TDI_RECEIVE_NORMAL\n"); } if (ulReceiveDatagramFlags & TDI_RECEIVE_EXPEDITED) // shouldn't see for datagram { DebugPrint0("TDI_RECEIVE_EXPEDITED\n"); } if (ulReceiveDatagramFlags & TDI_RECEIVE_PEEK) { DebugPrint0("TDI_RECEIVE_PEEK\n"); } if (ulReceiveDatagramFlags & TDI_RECEIVE_NO_RESPONSE_EXP) // not for datagrams { DebugPrint0("TDI_RECEIVE_NO_RESPONSE_EXP\n"); } if (ulReceiveDatagramFlags & TDI_RECEIVE_COPY_LOOKAHEAD) { DebugPrint0("TDI_RECEIVE_COPY_LOOKAHEAD\n"); } if (ulReceiveDatagramFlags & TDI_RECEIVE_ENTIRE_MESSAGE) { DebugPrint0("TDI_RECEIVE_ENTIRE_MESSAGE\n"); } if (ulReceiveDatagramFlags & TDI_RECEIVE_AT_DISPATCH_LEVEL) { DebugPrint0("TDI_RECEIVE_AT_DISPATCH_LEVEL\n"); } } /////////////////////////////////////////////////////////////////////////////// // end of file rcvdgram.cpp ///////////////////////////////////////////////////////////////////////////////