📄 tcpecho.c
字号:
ASSERT( pConnection );
if( !pConnection )
{
return( STATUS_INSUFFICIENT_RESOURCES );
}
pTCPDeviceObject = IoGetRelatedDeviceObject(
pConnection->m_KS_Endpoint.m_pFileObject
);
//
// Save Remote Client Address
//
NdisMoveMemory(
&pConnection->m_RemoteAddress,
RemoteAddress,
sizeof( TA_IP_ADDRESS )
);
#if DBG
DEBUG_DumpTransportAddress(
(PTRANSPORT_ADDRESS )&pConnection->m_RemoteAddress
);
#endif
//
// Allocate Resources To Call TDI To Accept
//
pConnection->m_pAcceptIrp = IoAllocateIrp(
pTCPDeviceObject->StackSize,
FALSE
);
ASSERT( pConnection->m_pAcceptIrp );
if( !pConnection->m_pAcceptIrp )
return( STATUS_INSUFFICIENT_RESOURCES );
//
// Build The Accept Request
//
pConnection->m_RemoteConnectionInfo.UserDataLength = 0;
pConnection->m_RemoteConnectionInfo.UserData = NULL;
pConnection->m_RemoteConnectionInfo.OptionsLength = 0;
pConnection->m_RemoteConnectionInfo.Options = NULL;
pConnection->m_RemoteConnectionInfo.RemoteAddressLength = sizeof( TA_IP_ADDRESS );
pConnection->m_RemoteConnectionInfo.RemoteAddress = &pConnection->m_RemoteAddress;
TdiBuildAccept(
pConnection->m_pAcceptIrp, // IRP
pTCPDeviceObject, // Pointer To TDI Device Object
pConnection->m_KS_Endpoint.m_pFileObject, // Connection Endpoint File Object
TCPS_ConnectedCallback,
pConnection,
&pConnection->m_RemoteConnectionInfo,
&pConnection->m_RemoteConnectionInfo
);
//
// Make the next stack location current. Normally IoCallDriver would
// do this, but for this IRP it has been bypassed.
//
IoSetNextIrpStackLocation( pConnection->m_pAcceptIrp );
//
// Place The New Connection In The Open Connection List
//
InsertTailList(
&g_OpenConnectionList,
&pConnection->m_ListElement
);
*hAcceptIrp = pConnection->m_pAcceptIrp;
*ConnectionContext = pConnection;
return( STATUS_MORE_PROCESSING_REQUIRED ); // Accept The Connection
}
/////////////////////////////////////////////////////////////////////////////
// S E N D R O U T I N E S //
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//// TCPS_EchoTcpPackets
//
// Purpose
// Call to handle packets queued on the ReceivedTcpPacketList.
//
// Parameters
//
// Return Value
//
// Remarks
//
VOID
TCPS_EchoTcpPackets(
PTCPS_Connection pConnection
)
{
//
// Echo TCP Packets
//
while( !IsListEmpty( &pConnection->m_ReceivedTcpPacketList ) )
{
PLIST_ENTRY linkage;
PTCPS_PACKET pTCPS_Packet;
PNDIS_BUFFER pNdisBuffer = NULL;
ULONG nDataSize, nByteCount, nBufferCount;
TDI_STATUS nTdiStatus;
//
// Find The Oldest Packet
//
linkage = RemoveHeadList( &pConnection->m_ReceivedTcpPacketList );
pTCPS_Packet = CONTAINING_RECORD(
linkage,
TCPS_PACKET,
Reserved.m_ListElement
);
//
// Check On State
//
if( !pConnection->m_bIsConnected || pConnection->m_bIsDisconnecting )
{
//
// Recycle The Packet And Buffers
//
TCPS_FreePacketAndBuffers( pTCPS_Packet );
continue;
}
//
// Query The NDIS_PACKET
// ---------------------
// NdisQueryPacket is called to locate the NDIS_BUFFER to be passed to
// TdiSend(). The nDataSize will be the unmodified original size of
// the buffer - *NOT* the amount of data which was transfered to the
// buffer by TDI.
//
NdisQueryPacket(
(PNDIS_PACKET )pTCPS_Packet,
(PULONG )NULL,
(PULONG )&nBufferCount,
&pNdisBuffer,
&nDataSize
);
if( !pNdisBuffer )
{
//
// Recycle The Packet And Buffers
//
TCPS_FreePacketAndBuffers( pTCPS_Packet );
return;
}
nTdiStatus = KS_SendOnEndpoint(
&pConnection->m_KS_Endpoint,
NULL, // User Completion Event
TCPS_SendCompletion, // User Completion Routine
pTCPS_Packet, // User Completion Context
&pTCPS_Packet->Reserved.m_PacketIoStatus,
pNdisBuffer, // MdlAddress
0 // Send Flags
);
if( !NT_SUCCESS( nTdiStatus ) )
{
break;
}
}
}
/////////////////////////////////////////////////////////////////////////////
//// TCPS_SendCompletion
//
// Purpose
// Called by TDI when the send operation completes.
//
// Parameters
//
// Return Value
//
// Remarks
//
VOID
TCPS_SendCompletion(
PVOID UserCompletionContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG Reserved
)
{
PTCPS_Connection pConnection;
PTCPS_PACKET pTCPS_Packet;
TDI_STATUS nTdiStatus;
PNDIS_BUFFER pNdisBuffer;
ULONG nDataSize, nBufferCount;
NTSTATUS nFinalStatus = IoStatusBlock->Status;
ULONG nByteCount = IoStatusBlock->Information;
#if DBG
DbgPrint( "TCPS_SendCompletion: FinalStatus: %d; BytesSent: %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_SendCompletion: Invalid Packet Signature\n" );
#endif
return;
}
pConnection = pTCPS_Packet->Reserved.m_pConnection;
if( !NT_SUCCESS( nFinalStatus ) )
{
// ATTENTION!!! Update Statistics???
}
//
// Possibly Send Another Packet
//
TCPS_EchoTcpPackets( pConnection );
//
// Query The NDIS_PACKET
//
NdisQueryPacket(
(PNDIS_PACKET )pTCPS_Packet,
(PULONG )NULL,
(PULONG )&nBufferCount,
&pNdisBuffer,
&nDataSize
);
if( !pNdisBuffer )
{
//
// Recycle The Packet And Buffers
//
TCPS_FreePacketAndBuffers( pTCPS_Packet );
return;
}
//
// Reset pNdisBuffer->Length
// -------------------------
// When the packet was received on this NDIS_BUFFER, the Length field
// was adjusted to the amount of data copied into the buffer. Here
// the Length field is reset to indicate the size of the buffer.
//
NdisAdjustBufferLength( pNdisBuffer, TCPS_BUFFER_SIZE );
#ifdef USE_RECEIVE_EVENT_HANDLER
//
// Recycle The Packet And Buffers
//
TCPS_FreePacketAndBuffers( pTCPS_Packet );
#else
//
// Check On State
//
if( !pConnection->m_bIsConnected || pConnection->m_bIsDisconnecting )
{
//
// Recycle The Packet And Buffers
//
TCPS_FreePacketAndBuffers( pTCPS_Packet );
}
else
{
//
// Start Another Receive On Same Buffer
//
KS_ReceiveOnEndpoint(
&pConnection->m_KS_Endpoint,
NULL, // User Completion Event
TCPS_ReceiveCompletion,// User Completion Routine
pTCPS_Packet, // User Completion Context
&pTCPS_Packet->Reserved.m_PacketIoStatus,
pNdisBuffer, // MdlAddress
0 // Flags
);
}
#endif // USE_RECEIVE_EVENT_HANDLER
return;
}
/////////////////////////////////////////////////////////////////////////////
// R E C E I V E R O U T I N E S //
/////////////////////////////////////////////////////////////////////////////
#ifdef USE_RECEIVE_EVENT_HANDLER
/////////////////////////////////////////////////////////////////////////////
//// TCPS_TransferDataCallback
//
// Purpose
// Called by TDI when the receive data transfer initiated by ClientEventReceive
// or TdiReceive completes.
//
// Parameters
//
// Return Value
//
// Remarks
// For non-error cases, this function saves the number of bytes which TDI
// has copied into the buffer and then queues the TCPS_Packet in the
// ReceivedTcpPacketList. It then calls a routine which can send the packet
// back to the originator.
//
NTSTATUS
TCPS_TransferDataCallback(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN PVOID pContext
)
{
PTCPS_Connection pConnection;
PTCPS_PACKET pTCPS_Packet;
PNDIS_BUFFER pNdisBuffer;
ULONG nDataSize, nBufferCount;
NTSTATUS nFinalStatus = pIrp->IoStatus.Status;
ULONG nByteCount = pIrp->IoStatus.Information;
#if DBG
DbgPrint( "TCPS_TransferDataCallback: FinalStatus: %d; Bytes Transfered: %d\n",
nFinalStatus, nByteCount );
#endif
pTCPS_Packet = (PTCPS_PACKET )pContext;
//
// Sanity Checks
//
ASSERT( pTCPS_Packet );
if( !pTCPS_Packet )
{
IoFreeIrp( pIrp );
return( STATUS_MORE_PROCESSING_REQUIRED );
}
//
// 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_TransferDataCallback: Invalid Packet Signature\n" );
#endif
IoFreeIrp( pIrp );
return( STATUS_MORE_PROCESSING_REQUIRED );
}
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 );
IoFreeIrp( pIrp );
return( STATUS_MORE_PROCESSING_REQUIRED );
}
//
// Handle Transfer Failure
//
if( !NT_SUCCESS( nFinalStatus ) )
{
//
// Recycle The Packet And Buffers
//
TCPS_FreePacketAndBuffers( pTCPS_Packet );
// ATTENTION!!! Update Statistics???
IoFreeIrp( pIrp );
return( STATUS_MORE_PROCESSING_REQUIRED );
}
// ATTENTION!!! Update Statistics???
//
// Query The NDIS_PACKET
// ---------------------
// NdisQueryPacket is called to locate the NDIS_BUFFER to be passed to
// TdiSend(). The nDataSize will be the unmodified original size of
// the buffer - *NOT* the amount of data which was transfered to the
// buffer by TDI.
//
NdisQueryPacket(
(PNDIS_PACKET )pTCPS_Packet,
(PULONG )NULL,
(PULONG )&nBufferCount,
&pNdisBuffer,
&nDataSize
);
ASSERT( pNdisBuffer );
if( !pNdisBuffer )
{
//
// Recycle The Packet And Buffers
//
TCPS_FreePacketAndBuffers( pTCPS_Packet );
IoFreeIrp( pIrp );
return( STATUS_MORE_PROCESSING_REQUIRED );
}
//
// 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -