📄 write.c
字号:
//
// release ownership of the NdisAdapter binding
//
NPF_StopUsingBinding(Open);
return 0;
}
// Reset the event used to synchronize packet allocation
NdisResetEvent(&Open->WriteEvent);
// Reset the pending packets counter
Open->Multiple_Write_Counter = 0;
// Start from the first packet
winpcap_hdr = (struct sf_pkthdr*)UserBuff;
// Retrieve the time references
StartTicks = KeQueryPerformanceCounter(&TimeFreq);
BufStartTime.tv_sec = winpcap_hdr->ts.tv_sec;
BufStartTime.tv_usec = winpcap_hdr->ts.tv_usec;
// Chech the consistency of the user buffer
if( (PCHAR)winpcap_hdr + winpcap_hdr->caplen + sizeof(struct sf_pkthdr) > EndOfUserBuff )
{
IF_LOUD(DbgPrint("Buffered Write: bogus packet buffer\n");)
//
// release ownership of the NdisAdapter binding
//
NPF_StopUsingBinding(Open);
return -1;
}
// Save the current time stamp counter
CurTicks = KeQueryPerformanceCounter(NULL);
//
// Main loop: send the buffer to the wire
//
while(TRUE)
{
if(winpcap_hdr->caplen ==0 || winpcap_hdr->caplen > Open->MaxFrameSize)
{
// Malformed header
IF_LOUD(DbgPrint("NPF_BufferedWrite: malformed or bogus user buffer, aborting write.\n");)
//
// release ownership of the NdisAdapter binding
//
NPF_StopUsingBinding(Open);
return -1;
}
// Allocate an MDL to map the packet data
TmpMdl = IoAllocateMdl((PCHAR)winpcap_hdr + sizeof(struct sf_pkthdr),
winpcap_hdr->caplen,
FALSE,
FALSE,
NULL);
if (TmpMdl == NULL)
{
// Unable to map the memory: packet lost
IF_LOUD(DbgPrint("NPF_BufferedWrite: unable to allocate the MDL.\n");)
//
// release ownership of the NdisAdapter binding
//
NPF_StopUsingBinding(Open);
return -1;
}
MmBuildMdlForNonPagedPool(TmpMdl); // XXX can this line be removed?
// Allocate a packet from our free list
NdisAllocatePacket( &Status, &pPacket, Open->PacketPool);
// If asked, set the flags for this packet.
// Currently, the only situation in which we set the flags is to disable the reception of loopback
// packets, i.e. of the packets sent by us.
if(Open->SkipSentPackets)
{
NdisSetPacketFlags(
pPacket,
g_SendPacketFlags);
}
if (Status != NDIS_STATUS_SUCCESS)
{
// No more free packets
IF_LOUD(DbgPrint("NPF_BufferedWrite: no more free packets, returning.\n");)
NdisResetEvent(&Open->WriteEvent);
NdisWaitEvent(&Open->WriteEvent, 1000);
// Try again to allocate a packet
NdisAllocatePacket( &Status, &pPacket, Open->PacketPool);
if(Open->SkipSentPackets)
{
NdisSetPacketFlags(
pPacket,
g_SendPacketFlags);
}
if (Status != NDIS_STATUS_SUCCESS)
{
// Second failure, report an error
IoFreeMdl(TmpMdl);
//
// release ownership of the NdisAdapter binding
//
NPF_StopUsingBinding(Open);
return -1;
}
// IoFreeMdl(TmpMdl);
// return (PCHAR)winpcap_hdr - UserBuff;
}
// The packet has a buffer that needs to be freed after every single write
RESERVED(pPacket)->FreeBufAfterWrite = TRUE;
TmpMdl->Next = NULL;
// Attach the MDL to the packet
NdisChainBufferAtFront(pPacket, TmpMdl);
// Increment the number of pending sends
InterlockedIncrement(&Open->Multiple_Write_Counter);
// Call the MAC
NdisSend( &Status, Open->AdapterHandle, pPacket);
if (Status != NDIS_STATUS_PENDING) {
// The send didn't pend so call the completion handler now
NPF_SendComplete(
Open,
pPacket,
Status
);
}
// Step to the next packet in the buffer
(PCHAR)winpcap_hdr += winpcap_hdr->caplen + sizeof(struct sf_pkthdr);
// Check if the end of the user buffer has been reached
if( (PCHAR)winpcap_hdr >= EndOfUserBuff )
{
IF_LOUD(DbgPrint("NPF_BufferedWrite: End of buffer.\n");)
// Wait the completion of pending sends
NPF_WaitEndOfBufferedWrite(Open);
//
// release ownership of the NdisAdapter binding
//
NPF_StopUsingBinding(Open);
return (INT)((PCHAR)winpcap_hdr - UserBuff);
}
if( Sync ){
// Release the application if it has been blocked for approximately more than 1 seconds
if( winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec > 1 )
{
IF_LOUD(DbgPrint("NPF_BufferedWrite: timestamp elapsed, returning.\n");)
// Wait the completion of pending sends
NPF_WaitEndOfBufferedWrite(Open);
//
// release ownership of the NdisAdapter binding
//
NPF_StopUsingBinding(Open);
return (INT)((PCHAR)winpcap_hdr - UserBuff);
}
// Calculate the time interval to wait before sending the next packet
TargetTicks.QuadPart = StartTicks.QuadPart +
(LONGLONG)((winpcap_hdr->ts.tv_sec - BufStartTime.tv_sec) * 1000000 +
winpcap_hdr->ts.tv_usec - BufStartTime.tv_usec) *
(TimeFreq.QuadPart) / 1000000;
// Wait until the time interval has elapsed
while( CurTicks.QuadPart <= TargetTicks.QuadPart )
CurTicks = KeQueryPerformanceCounter(NULL);
}
}
//
// release ownership of the NdisAdapter binding
//
NPF_StopUsingBinding(Open);
return (INT)((PCHAR)winpcap_hdr - UserBuff);
}
//-------------------------------------------------------------------
VOID NPF_WaitEndOfBufferedWrite(POPEN_INSTANCE Open)
{
UINT i;
NdisResetEvent(&Open->WriteEvent);
for(i=0; Open->Multiple_Write_Counter > 0 && i < TRANSMIT_PACKETS; i++)
{
NdisWaitEvent(&Open->WriteEvent, 100);
NdisResetEvent(&Open->WriteEvent);
}
return;
}
//-------------------------------------------------------------------
VOID
NPF_SendComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pPacket,
IN NDIS_STATUS Status
)
{
POPEN_INSTANCE Open;
PMDL TmpMdl;
TRACE_ENTER();
Open= (POPEN_INSTANCE)ProtocolBindingContext;
if( RESERVED(pPacket)->FreeBufAfterWrite )
{
//
// Packet sent by NPF_BufferedWrite()
//
// Free the MDL associated with the packet
NdisUnchainBufferAtFront(pPacket, &TmpMdl);
IoFreeMdl(TmpMdl);
// recyle the packet
// NdisReinitializePacket(pPacket);
NdisFreePacket(pPacket);
// Increment the number of pending sends
InterlockedDecrement(&Open->Multiple_Write_Counter);
NdisSetEvent(&Open->WriteEvent);
TRACE_EXIT();
return;
}
else
{
//
// Packet sent by NPF_Write()
//
ULONG stillPendingPackets = InterlockedDecrement(&Open->TransmitPendingPackets);
//
// Put the packet back on the free list
//
NdisFreePacket(pPacket);
//
// if the number of packets submitted to NdisSend and not acknoledged is less than half the
// packets in the TX pool, wake up any transmitter waiting for available packets in the TX
// packet pool
//
if (stillPendingPackets < TRANSMIT_PACKETS/2)
{
NdisSetEvent(&Open->WriteEvent);
}
else
{
//
// otherwise, reset the event, so that we are sure that the NPF_Write will eventually block to
// waitg for availability of packets in the TX packet pool
//
NdisResetEvent(&Open->WriteEvent);
}
if(stillPendingPackets == 0)
{
NdisSetEvent(&Open->NdisWriteCompleteEvent);
}
TRACE_EXIT();
return;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -