📄 read.c
字号:
/*
* Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
* Copyright (c) 2005 - 2006 CACE Technologies, Davis (California)
* 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, CACE Technologies
* 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"
#include "win_bpf.h"
#include "tme.h"
#include "time_calls.h"
extern struct time_conv G_Start_Time; // from openclos.c
extern ULONG NCpu; //from packet.c
NTSTATUS NPF_Read(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
POPEN_INSTANCE Open;
PIO_STACK_LOCATION IrpSp;
PUCHAR packp;
ULONG Input_Buffer_Length;
UINT Thead;
UINT Ttail;
UINT TLastByte;
PUCHAR CurrBuff;
LARGE_INTEGER CapTime;
LARGE_INTEGER TimeFreq;
struct bpf_hdr *header;
KIRQL Irql;
PUCHAR UserPointer;
ULONG bytecopy;
UINT SizeToCopy;
UINT PktLen;
ULONG copied,count,current_cpu,av,plen,increment,ToCopy,available;
CpuPrivateData *LocalData;
ULONG i;
ULONG Occupation;
IF_LOUD(DbgPrint("NPF: Read\n");)
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Open=IrpSp->FileObject->FsContext;
//
// we need to test if the device is still bound to the Network adapter,
// so we perform a start/stop using binding.
// This is not critical, since we just want to have a quick way to have the
// dispatch read fail in case the adapter has been unbound
if(NPF_StartUsingBinding(Open) == FALSE)
{
// The Network adapter has been removed or diasabled
EXIT_FAILURE(0);
}
NPF_StopUsingBinding(Open);
if (Open->Size == 0)
{
EXIT_FAILURE(0);
}
if( Open->mode & MODE_DUMP && Open->DumpFileHandle == NULL ){
// this instance is in dump mode, but the dump file has still not been opened
EXIT_FAILURE(0);
}
Occupation=0;
for(i=0;i<NCpu;i++)
Occupation += (Open->Size - Open->CpuData[i].Free);
//See if the buffer is full enough to be copied
if( Occupation <= Open->MinToCopy*NCpu || Open->mode & MODE_DUMP )
{
if (Open->ReadEvent != NULL)
{
//wait until some packets arrive or the timeout expires
if(Open->TimeOut.QuadPart != (LONGLONG)IMMEDIATE)
KeWaitForSingleObject(Open->ReadEvent,
UserRequest,
KernelMode,
TRUE,
(Open->TimeOut.QuadPart == (LONGLONG)0)? NULL: &(Open->TimeOut));
KeClearEvent(Open->ReadEvent);
}
if(Open->mode & MODE_STAT)
{ //this capture instance is in statistics mode
#ifdef NDIS50
CurrBuff=(PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
#else
CurrBuff=(PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress);
#endif
if (CurrBuff == NULL)
{
EXIT_FAILURE(0);
}
//fill the bpf header for this packet
header=(struct bpf_hdr*)CurrBuff;
GET_TIME(&header->bh_tstamp,&G_Start_Time);
if(Open->mode & MODE_DUMP){
*(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr)+16)=Open->DumpOffset.QuadPart;
header->bh_caplen=24;
header->bh_datalen=24;
Irp->IoStatus.Information = 24 + sizeof(struct bpf_hdr);
}
else{
header->bh_caplen=16;
header->bh_datalen=16;
header->bh_hdrlen=sizeof(struct bpf_hdr);
Irp->IoStatus.Information = 16 + sizeof(struct bpf_hdr);
}
*(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr))=Open->Npackets.QuadPart;
*(LONGLONG*)(CurrBuff+sizeof(struct bpf_hdr)+8)=Open->Nbytes.QuadPart;
//reset the countetrs
NdisAcquireSpinLock( &Open->CountersLock );
Open->Npackets.QuadPart=0;
Open->Nbytes.QuadPart=0;
NdisReleaseSpinLock( &Open->CountersLock );
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//
// The MONITOR_MODE (aka TME extensions) is not supported on
// 64 bit architectures
//
#ifdef __NPF_x86__
if(Open->mode==MODE_MON) //this capture instance is in monitor mode
{
PTME_DATA data;
ULONG cnt;
ULONG block_size;
PUCHAR tmp;
#ifdef NDIS50
UserPointer=MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
#else
UserPointer=MmGetSystemAddressForMdl(Irp->MdlAddress);
#endif
if (UserPointer == NULL)
{
EXIT_FAILURE(0);
}
if ((!IS_VALIDATED(Open->tme.validated_blocks,Open->tme.active_read))||(IrpSp->Parameters.Read.Length<sizeof(struct bpf_hdr)))
{
EXIT_FAILURE(0);
}
header=(struct bpf_hdr*)UserPointer;
GET_TIME(&header->bh_tstamp,&G_Start_Time);
header->bh_hdrlen=sizeof(struct bpf_hdr);
//moves user memory pointer
UserPointer+=sizeof(struct bpf_hdr);
//calculus of data to be copied
//if the user buffer is smaller than data to be copied,
//only some data will be copied
data=&Open->tme.block_data[Open->tme.active_read];
if (data->last_read.tv_sec!=0)
data->last_read=header->bh_tstamp;
bytecopy=data->block_size*data->filled_blocks;
if ((IrpSp->Parameters.Read.Length-sizeof(struct bpf_hdr))<bytecopy)
bytecopy=(IrpSp->Parameters.Read.Length-sizeof(struct bpf_hdr))/ data->block_size;
else
bytecopy=data->filled_blocks;
tmp=data->shared_memory_base_address;
block_size=data->block_size;
for (cnt=0;cnt<bytecopy;cnt++)
{
NdisAcquireSpinLock(&Open->MachineLock);
RtlCopyMemory(UserPointer,tmp,block_size);
NdisReleaseSpinLock(&Open->MachineLock);
tmp+=block_size;
UserPointer+=block_size;
}
bytecopy*=block_size;
header->bh_caplen=bytecopy;
header->bh_datalen=header->bh_caplen;
EXIT_SUCCESS(bytecopy+sizeof(struct bpf_hdr));
}
Occupation=0;
for(i=0;i<NCpu;i++)
Occupation += (Open->Size - Open->CpuData[i].Free);
if ( Occupation == 0 || Open->mode & MODE_DUMP)
// The timeout has expired, but the buffer is still empty (or the packets must be written to file).
// We must awake the application, returning an empty buffer.
{
EXIT_SUCCESS(0);
}
#else // not __NPF_x86__ , so x86-64 or IA64
if(Open->mode==MODE_MON) //this capture instance is in monitor mode
{
EXIT_FAILURE(0);
}
#endif // __NPF_x86__
}
//------------------------------------------------------------------------------
copied=0;
count=0;
current_cpu=0;
available = IrpSp->Parameters.Read.Length;
#ifdef NDIS50
packp=(PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
#else
packp=(PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress);
#endif
if (packp == NULL)
{
EXIT_FAILURE(0);
}
if (Open->ReadEvent != NULL)
KeClearEvent(Open->ReadEvent);
while (count < NCpu) //round robin on the CPUs, if count = NCpu there are no packets left to be copied
{
if (available == copied)
{
EXIT_SUCCESS(copied);
}
LocalData = &Open->CpuData[current_cpu];
if (LocalData->Free < Open->Size)
{ //there are some packets in the selected (aka LocalData) buffer
struct PacketHeader *Header = (struct PacketHeader*)(LocalData->Buffer + LocalData->C);
if ( Header->SN == Open->ReaderSN)
{ //check if it the next one to be copied
plen = Header->header.bh_caplen;
if (plen + sizeof (struct bpf_hdr) > available - copied)
{ //if the packet does not fit into the user buffer, we've ended copying packets
EXIT_SUCCESS(copied);
}
// FIX_TIMESTAMPS(&Header->header.bh_tstamp);
*((struct bpf_hdr*)(&packp[copied]))=Header->header;
copied += sizeof(struct bpf_hdr);
LocalData->C += sizeof(struct PacketHeader);
if (LocalData->C == Open->Size)
LocalData->C = 0;
if (Open->Size - LocalData->C < plen)
{
//the packet is fragmented in the buffer (i.e. it skips the buffer boundary)
ToCopy = Open->Size - LocalData->C;
RtlCopyMemory(packp + copied,LocalData->Buffer + LocalData->C,ToCopy);
RtlCopyMemory(packp + copied + ToCopy,LocalData->Buffer,plen-ToCopy);
LocalData->C = plen-ToCopy;
}
else
{
//the packet is not fragmented
RtlCopyMemory(packp + copied ,LocalData->Buffer + LocalData->C ,plen);
LocalData->C += plen;
// if (c==size) inutile, contemplato nell "header atomico"
// c=0;
}
Open->ReaderSN++;
copied+=Packet_WORDALIGN(plen);
increment = plen + sizeof(struct PacketHeader);
if ( Open->Size - LocalData->C < sizeof(struct PacketHeader))
{ //the next packet would be saved at the end of the buffer, but the NewHeader struct would be fragmented
//so the producer (--> the consumer) skips to the beginning of the buffer
increment += Open->Size-LocalData->C;
LocalData->C=0;
}
InterlockedExchangeAdd(&Open->CpuData[current_cpu].Free,increment);
count=0;
}
else
{
current_cpu=(current_cpu+1)%NCpu;
count++;
}
}
else
{
current_cpu=(current_cpu+1)%NCpu;
count++;
}
}
{EXIT_SUCCESS(copied);}
//------------------------------------------------------------------------------
}
NDIS_STATUS NPF_tap (IN NDIS_HANDLE ProtocolBindingContext,IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,IN UINT HeaderBufferSize,IN PVOID LookaheadBuffer,
IN UINT LookaheadBufferSize,IN UINT PacketSize)
{
POPEN_INSTANCE Open;
PNDIS_PACKET pPacket;
ULONG SizeToTransfer;
NDIS_STATUS Status;
UINT BytesTransfered;
ULONG BufferLength;
PMDL pMdl1,pMdl2;
LARGE_INTEGER CapTime;
LARGE_INTEGER TimeFreq;
UINT fres;
USHORT NPFHdrSize;
CpuPrivateData *LocalData;
ULONG Cpu;
struct PacketHeader *Header;
ULONG ToCopy;
ULONG increment;
ULONG i;
BOOLEAN ShouldReleaseBufferLock;
IF_VERY_LOUD(DbgPrint("NPF: tap\n");)
IF_VERY_LOUD(DbgPrint("HeaderBufferSize=%u, LookAheadBuffer=%p, LookaheadBufferSize=%u, PacketSize=%u\n",
HeaderBufferSize,
LookaheadBuffer,
LookaheadBufferSize,
PacketSize);)
Open= (POPEN_INSTANCE)ProtocolBindingContext;
Cpu = KeGetCurrentProcessorNumber();
LocalData = &Open->CpuData[Cpu];
LocalData->Received++;
IF_LOUD(DbgPrint("Received on CPU %d \t%d\n",Cpu,LocalData->Received);)
// Open->Received++; // Number of packets received by filter ++
NdisAcquireSpinLock(&Open->MachineLock);
//
//Check if the lookahead buffer follows the mac header.
//If the data follow the header (i.e. there is only a buffer) a normal bpf_filter() is
//executed on the packet.
//Otherwise if there are 2 separate buffers (this could be the case of LAN emulation or
//things like this) bpf_filter_with_2_buffers() is executed.
//
if((UINT)((PUCHAR)LookaheadBuffer-(PUCHAR)HeaderBuffer) != HeaderBufferSize)
fres=bpf_filter_with_2_buffers((struct bpf_insn*)(Open->bpfprogram),
HeaderBuffer,
LookaheadBuffer,
HeaderBufferSize,
PacketSize+HeaderBufferSize,
LookaheadBufferSize+HeaderBufferSize,
&Open->mem_ex,
&Open->tme,
&G_Start_Time);
else
//
// the jit filter is available on x86 (32 bit) only
//
#ifdef __NPF_x86__
if(Open->Filter != NULL)
{
if (Open->bpfprogram != NULL)
{
fres=Open->Filter->Function(HeaderBuffer,
PacketSize+HeaderBufferSize,
LookaheadBufferSize+HeaderBufferSize);
}
else
fres = -1;
}
else
#endif //__NPF_x86__
fres=bpf_filter((struct bpf_insn*)(Open->bpfprogram),
HeaderBuffer,
PacketSize+HeaderBufferSize,
LookaheadBufferSize+HeaderBufferSize,
&Open->mem_ex,
&Open->tme,
&G_Start_Time);
NdisReleaseSpinLock(&Open->MachineLock);
//
// The MONITOR_MODE (aka TME extensions) is not supported on
// 64 bit architectures
//
#ifdef __NPF_x86__
if(Open->mode==MODE_MON)
// we are in monitor mode
{
if (fres==1)
{
if (Open->ReadEvent != NULL)
{
KeSetEvent(Open->ReadEvent,0,FALSE);
}
}
return NDIS_STATUS_NOT_ACCEPTED;
}
#endif
if(fres==0)
{
// Packet not accepted by the filter, ignore it.
return NDIS_STATUS_NOT_ACCEPTED;
}
//if the filter returns -1 the whole packet must be accepted
if(fres == -1 || fres > PacketSize+HeaderBufferSize)
fres = PacketSize+HeaderBufferSize;
if(Open->mode & MODE_STAT)
{
// we are in statistics mode
NdisAcquireSpinLock( &Open->CountersLock );
Open->Npackets.QuadPart++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -