📄 tcpecho.c
字号:
//
NdisAdjustBufferLength( pNdisBuffer, nByteCount );
// ATTENTION!!! Check Flags???
IoFreeIrp( pIrp ); // Don't Access pIrp Any More...
//
// Put The Packet In The Connection's Received TCP PacketList
//
InsertTailList(
&pConnection->m_ReceivedTcpPacketList,
&pTCPS_Packet->Reserved.m_ListElement
);
//
// Possibly Send Another Packet
//
TCPS_EchoTcpPackets( pConnection );
return( STATUS_MORE_PROCESSING_REQUIRED );
}
/////////////////////////////////////////////////////////////////////////////
//// TCPS_ReceiveEventHandler
//
// Purpose
// Called by the TDI when incomming data arrives on the connection.
//
// Parameters
//
// Return Value
//
// Remarks
// This handler is NOT called if there is an outstanding TdiReceive or
// we have not accepted all previously indicated data.
//
// Although some data (perhaps all) is available at pReceivedData, it is
// best to handle received data as a two-step operation - which actually
// parallels the two-step reception operation of the underlying protocol
// driver.
//
// The first step in reception is when the received data is "indicated"
// here at the TCPS_ReceiveEventHandler. Here the data at Tsdu and
// the associated ReceiveFlags can be examined to determine if the data
// is of further interest.
//
// If the data is of interest, then resources should be allocated and
// the ??? setup to have the underlying TDI driver transfer
// the data. When transfer is complete, the TCPS_ReceiveCompletion
// callback will ba called.
//
// In the TCPS_ReceiveCompletion the data, which we will then own,
// can be processed further. In the case of the ECHO client, it can be
// sent back to the remote network client.
//
// ***** TDI Client (US) ***** * TDI Protocol Driver (MSTCP) *
// TCPS_ReceiveEventHandler ReceiveHandler
// TCPS_TransferDataCallback TransferDataComplete
//
NTSTATUS
TCPS_ReceiveEventHandler(
IN PVOID TdiEventContext, // Context From SetEventHandler
IN CONNECTION_CONTEXT ConnectionContext, // Contect From Accept
IN ULONG ReceiveFlags,
IN ULONG BytesIndicated,
IN ULONG BytesAvailable,
OUT ULONG *BytesTaken,
IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
)
{
PTCPS_Connection pConnection;
PTCPS_PACKET pTCPS_Packet;
NDIS_STATUS nNdisStatus;
PNDIS_BUFFER pNdisBuffer;
PDEVICE_OBJECT pTCPDeviceObject;
#if DBG
DbgPrint( "TCPS_ReceiveEventHandler Entry...\n" );
DbgPrint( "BytesIndicated: %d, BytesAvailable: %d; ReceiveFlags: 0x%X\n",
BytesIndicated, BytesAvailable, ReceiveFlags );
#endif
pConnection = (PTCPS_Connection )ConnectionContext;
//
// Check On State
//
if( !pConnection->m_bIsConnected || pConnection->m_bIsDisconnecting )
{
//
// Tell TDI That All Data Was Taken
//
*BytesTaken = BytesIndicated;
return( STATUS_SUCCESS );
}
//
// Allocate The Receive Packet Descriptor
// --------------------------------------
// Use of this structure is adopted from it's use in lower-level
// NDIS protocol drivers. It is simply a convienient way to allocate
// the space needed to handle packet reception.
//
NdisAllocatePacket(
&nNdisStatus,
&(PNDIS_PACKET )pTCPS_Packet,
g_hPacketPool
);
if( nNdisStatus != NDIS_STATUS_SUCCESS || !pTCPS_Packet )
{
// ATTENTION!!! Update Statistics???
#if DBG
DbgPrint( "TCPS_ReceiveEventHandler Could Not Allocate Packet\n" );
#endif
//
// Tell TDI That No Data Was Taken
// -------------------------------
// TDI will attempt to buffer the data for later consumption or
// the data will be retransmitted. Special steps may be needed to
// force the TDI driver to indicate the data not taken at a later
// time when resources become available.
//
*BytesTaken = 0;
return( STATUS_SUCCESS );
}
//
// Initialize The Packet Signature
//
pTCPS_Packet->Reserved.m_Signature = TCPS_PACKET_SIGN;
//
// Save Connection Pointer For Use In Callback Routine
//
pTCPS_Packet->Reserved.m_pConnection = pConnection;
//
// Save Bytes Taken In Internal Buffer
// -----------------------------------
// In this sample the data is saved in an internal buffer that is a
// field in the TCPS_PACKET structure.
//
// ATTENTION!!! Note that *BytesTaken is set in the following statement.
//
if( BytesIndicated <= TCPS_BUFFER_SIZE )
{
*BytesTaken = BytesIndicated;
}
else
{
*BytesTaken = TCPS_BUFFER_SIZE;
}
NdisMoveMemory(
pTCPS_Packet->Reserved.m_DataBuffer,
Tsdu,
*BytesTaken
);
//
// Allocate An NDIS Buffer Descriptor For The Receive Data
//
NdisAllocateBuffer(
&nNdisStatus,
&pNdisBuffer,
g_hBufferPool,
pTCPS_Packet->Reserved.m_DataBuffer, // Private Buffer
*BytesTaken
);
if( nNdisStatus != NDIS_STATUS_SUCCESS || !pNdisBuffer )
{
// ATTENTION!!! Update Statistics???
NdisFreePacket( (PNDIS_PACKET )pTCPS_Packet );
#if DBG
DbgPrint( "TCPS_ReceiveEventHandler Could Not Allocate Buffer\n" );
#endif
//
// Tell TDI That No Data Was Taken
// -------------------------------
// TDI will attempt to buffer the data for later consumption or
// the data will be retransmitted. Special steps may be needed to
// force the TDI driver to indicate the data not taken at a later
// time when resources become available.
//
*BytesTaken = 0;
return( STATUS_SUCCESS );
}
NdisChainBufferAtFront( (PNDIS_PACKET )pTCPS_Packet, pNdisBuffer );
//
// Put The Packet In The Connection's Received TCP PacketList
//
InsertTailList(
&pConnection->m_ReceivedTcpPacketList,
&pTCPS_Packet->Reserved.m_ListElement
);
//
// Determine Whether Tsdu Contains A Full TSDU
// -------------------------------------------
// We could check (ReceiveDatagramFlags & TDI_RECEIVE_ENTIRE_MESSAGE).
// However, checking (BytesIndicated == BytesAvailable) seems more
// reliable.
//
if( *BytesTaken == BytesAvailable )
{
//
// Possibly Send Another Packet
//
TCPS_EchoTcpPackets( pConnection );
return( STATUS_SUCCESS );
}
//
// Allocate Another Receive Packet Descriptor
// ------------------------------------------
// Use of this structure is adopted from it's use in lower-level
// NDIS protocol drivers. It is simply a convienient way to allocate
// the space needed to handle packet reception.
//
NdisAllocatePacket(
&nNdisStatus,
&(PNDIS_PACKET )pTCPS_Packet,
g_hPacketPool
);
if( nNdisStatus != NDIS_STATUS_SUCCESS || !pTCPS_Packet )
{
// ATTENTION!!! Update Statistics???
#if DBG
DbgPrint( "TCPS_ReceiveEventHandler Could Not Allocate Packet\n" );
#endif
return( STATUS_SUCCESS );
}
//
// Initialize The Packet Signature
//
pTCPS_Packet->Reserved.m_Signature = TCPS_PACKET_SIGN;
//
// Save Connection Pointer For Use In Callback Routine
//
pTCPS_Packet->Reserved.m_pConnection = pConnection;
//
// Process Partial TSDU
// --------------------
// One could check (ReceiveDatagramFlags & TDI_RECEIVE_COPY_LOOKAHEAD) to
// determine whether copying the BytesIndicated lookahead data is
// required or not. However, since the case where lookahead data must
// be copied must be dealt with anyway, it seems simpler to just go ahead
// and always copy the lookahead data here in the handler.
//
// Allocate An NDIS Buffer Descriptor For The Receive Data
//
NdisAllocateBuffer(
&nNdisStatus,
&pNdisBuffer,
g_hBufferPool,
pTCPS_Packet->Reserved.m_DataBuffer, // Private Buffer
BytesAvailable - *BytesTaken
);
if( nNdisStatus != NDIS_STATUS_SUCCESS || !pNdisBuffer )
{
// ATTENTION!!! Update Statistics???
NdisFreePacket( (PNDIS_PACKET )pTCPS_Packet );
#if DBG
DbgPrint( "TCPS_ReceiveEventHandler Could Not Allocate Buffer\n" );
#endif
return( STATUS_SUCCESS );
}
NdisChainBufferAtFront( (PNDIS_PACKET )pTCPS_Packet, pNdisBuffer );
//
// Allocate Resources To Call TDI To Transfer Received Data
//
pTCPDeviceObject = IoGetRelatedDeviceObject(
pConnection->m_KS_Endpoint.m_pFileObject
);
pTCPS_Packet->Reserved.m_pReceiveIrp = IoAllocateIrp(
pTCPDeviceObject->StackSize,
FALSE
);
ASSERT( pTCPS_Packet->Reserved.m_pReceiveIrp );
if( !pTCPS_Packet->Reserved.m_pReceiveIrp )
{
TCPS_FreePacketAndBuffers( pTCPS_Packet );
return( STATUS_SUCCESS );
}
TdiBuildReceive(
pTCPS_Packet->Reserved.m_pReceiveIrp, // IRP
pTCPDeviceObject, // Pointer To TDI Device Object
pConnection->m_KS_Endpoint.m_pFileObject, // Connection Endpoint File Object
TCPS_TransferDataCallback, // CompletionRoutine
pTCPS_Packet, // Context
pNdisBuffer, // MdlAddress
0, // ReceiveFlags
BytesAvailable - *BytesTaken // ReceiveLength
);
//
// Make the next stack location current. Normally IoCallDriver would
// do this, but for this IRP it has been bypassed.
//
IoSetNextIrpStackLocation( pTCPS_Packet->Reserved.m_pReceiveIrp );
//
// Tell TDI To Transfer The Data
//
*IoRequestPacket = pTCPS_Packet->Reserved.m_pReceiveIrp;
return( STATUS_MORE_PROCESSING_REQUIRED );
}
#else
/////////////////////////////////////////////////////////////////////////////
//// TCPS_ReceiveCompletion
//
// Purpose
//
// Parameters
//
// Return Value
//
// Remarks
//
VOID
TCPS_ReceiveCompletion(
PVOID UserCompletionContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG Reserved
)
{
PTCPS_Connection pConnection;
PTCPS_PACKET pTCPS_Packet;
PNDIS_BUFFER pNdisBuffer;
ULONG nDataSize, nBufferCount;
NTSTATUS nFinalStatus = IoStatusBlock->Status;
ULONG nByteCount = IoStatusBlock->Information;
#if DBG
DbgPrint( "TCPS_ReceiveCompletion: FinalStatus: 0x%8.8x; Bytes Transfered: %d\n",
nFinalStatus, nByteCount );
#endif
pTCPS_Packet = (PTCPS_PACKET )UserCompletionContext;
//
// Sanity Check On Passed Parameters
//
ASSERT( pTCPS_Packet );
if( !pTCPS_Packet )
{
return;
}
//
// Verify The Packet Signature
//
ASSERT( pTCPS_Packet->Reserved.m_Signature == TCPS_PACKET_SIGN );
if( pTCPS_Packet->Reserved.m_Signature != TCPS_PACKET_SIGN )
{
#if DBG
DbgPrint( "TCPS_ReceiveCompletion: Invalid Packet Signature\n" );
#endif
return;
}
pConnection = pTCPS_Packet->Reserved.m_pConnection;
//
// Check On State
//
if( !pConnection->m_bIsConnected || pConnection->m_bIsDisconnecting )
{
//
// Recycle The Packet And Buffers
//
TCPS_FreePacketAndBuffers( pTCPS_Packet );
return;
}
//
// Handle Transfer Failure
//
if( !NT_SUCCESS( nFinalStatus ) )
{
//
// Recycle The Packet And Buffers
//
TCPS_FreePacketAndBuffers( pTCPS_Packet );
// ATTENTION!!! Update Statistics???
return;
}
// ATTENTION!!! Update Statistics???
//
// Query The NDIS_PACKET
//
NdisQueryPacket(
(PNDIS_PACKET )pTCPS_Packet,
(PULONG )NULL,
(PULONG )&nBufferCount,
&pNdisBuffer,
&nDataSize
);
ASSERT( pNdisBuffer );
if( !pNdisBuffer )
{
//
// Recycle The Packet And Buffers
//
TCPS_FreePacketAndBuffers( pTCPS_Packet );
return;
}
//
// Save The Byte Count
// -------------------
// In this implementation, the NDIS_BUFFER Length field is adjusted
// to the amount of data that was copied into the buffer. This has
// the added benefit of insuring that when the packet is sent later
// the NDIS_BUFFER Length field and the length parameter passed to
// TdiSend are the same.
//
NdisAdjustBufferLength( pNdisBuffer, nByteCount );
// ATTENTION!!! Check Flags???
//
// Put The Packet In The Connection's Received TCP PacketList
//
InsertTailList(
&pConnection->m_ReceivedTcpPacketList,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -