📄 write.c
字号:
/*
* Copyright (c) 1999 - 2003
* NetGroup, Politecnico di Torino (Italy)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Politecnico di Torino nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "stdarg.h"
#include "ntddk.h"
#include "ntiologc.h"
#include "ndis.h"
#include "debug.h"
#include "packet.h"
//-------------------------------------------------------------------
NTSTATUS
NPF_Write(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
PNDIS_PACKET pPacket;
UINT i;
NDIS_STATUS Status;
IF_LOUD(DbgPrint("NPF_Write\n");)
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Open=IrpSp->FileObject->FsContext;
if( Open->Bound == FALSE )
{
// The Network adapter was removed.
EXIT_FAILURE(0);
}
NdisAcquireSpinLock(&Open->WriteLock);
if(Open->WriteInProgress)
{
// Another write operation is currently in progress
EXIT_FAILURE(0);
}
else
{
Open->WriteInProgress = TRUE;
}
NdisReleaseSpinLock(&Open->WriteLock);
IF_LOUD(DbgPrint("Max frame size = %d\n", Open->MaxFrameSize);)
if(IrpSp->Parameters.Write.Length == 0 || // Check that the buffer provided by the user is not empty
Open->MaxFrameSize == 0 || // Check that the MaxFrameSize is correctly initialized
IrpSp->Parameters.Write.Length > Open->MaxFrameSize) // Check that the fame size is smaller that the MTU
{
IF_LOUD(DbgPrint("frame size out of range, send aborted\n");)
EXIT_FAILURE(0);
}
IoMarkIrpPending(Irp);
Open->Multiple_Write_Counter=Open->Nwrites;
NdisResetEvent(&Open->WriteEvent);
for(i=0;i<Open->Nwrites;i++){
// Try to get a packet from our list of free ones
NdisAllocatePacket(
&Status,
&pPacket,
Open->PacketPool
);
if (Status != NDIS_STATUS_SUCCESS) {
// No free packets
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
// The packet hasn't a buffer that needs not to be freed after every single write
RESERVED(pPacket)->FreeBufAfterWrite = FALSE;
// Save the IRP associated with the packet
RESERVED(pPacket)->Irp=Irp;
// Attach the writes buffer to the packet
NdisChainBufferAtFront(pPacket,Irp->MdlAddress);
// 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
);
}
if(i%100==99){
NdisWaitEvent(&Open->WriteEvent,1000);
NdisResetEvent(&Open->WriteEvent);
}
}
return(STATUS_PENDING);
}
//-------------------------------------------------------------------
INT
NPF_BufferedWrite(
IN PIRP Irp,
IN PCHAR UserBuff,
IN ULONG UserBuffSize,
BOOLEAN Sync)
{
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
PNDIS_PACKET pPacket;
UINT i;
NDIS_STATUS Status;
LARGE_INTEGER StartTicks, CurTicks, TargetTicks;
LARGE_INTEGER TimeFreq;
struct timeval BufStartTime;
struct sf_pkthdr *winpcap_hdr;
PMDL TmpMdl;
PCHAR CurPos;
PCHAR EndOfUserBuff = UserBuff + UserBuffSize;
IF_LOUD(DbgPrint("NPF: BufferedWrite, UserBuff=%x, Size=%u\n", UserBuff, UserBuffSize);)
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Open=IrpSp->FileObject->FsContext;
if( Open->Bound == FALSE ){
// The Network adapter was removed.
return 0;
}
// Sanity check on the user buffer
if(UserBuff==0)
{
return 0;
}
// Check that the MaxFrameSize is correctly initialized
if(Open->MaxFrameSize == 0)
{
IF_LOUD(DbgPrint("BufferedWrite: Open->MaxFrameSize not initialized, probably because of a problem in the OID query\n");)
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");)
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");)
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");)
return -1;
}
MmBuildMdlForNonPagedPool(TmpMdl); // XXX can this line be removed?
// Allocate a packet from our free list
NdisAllocatePacket( &Status, &pPacket, Open->PacketPool);
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 (Status != NDIS_STATUS_SUCCESS) {
// Second failure, report an error
IoFreeMdl(TmpMdl);
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);
return (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);
return (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);
}
}
return (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
)
{
PIRP Irp;
PIO_STACK_LOCATION irpSp;
POPEN_INSTANCE Open;
PMDL TmpMdl;
IF_LOUD(DbgPrint("NPF: SendComplete, BindingContext=%d\n",ProtocolBindingContext);)
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);
return;
}
else
{
//
// Packet sent by NPF_Write()
//
if((Open->Nwrites - Open->Multiple_Write_Counter) %100 == 99)
NdisSetEvent(&Open->WriteEvent);
Open->Multiple_Write_Counter--;
if(Open->Multiple_Write_Counter == 0){
// Release the buffer and awake the application
NdisUnchainBufferAtFront(pPacket, &TmpMdl);
// Complete the request
Irp=RESERVED(pPacket)->Irp;
irpSp = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = irpSp->Parameters.Write.Length;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
NdisAcquireSpinLock(&Open->WriteLock);
Open->WriteInProgress = FALSE;
NdisReleaseSpinLock(&Open->WriteLock);
}
// Put the packet back on the free list
NdisFreePacket(pPacket);
return;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -