庖丁解牛-----winpcap源码彻底解密(三)
上一篇讲了怎么发送数据包,这次接着讲怎么接收数据包,数据包过滤后,就被复制到内核缓冲区(kernel buffer),接收数据包的方式有2种,使用回调函数接收数据包,比如pcap_loop,pcap_dispatch,二是非回调函数的方式来接收数据包,如pcap_ next, pcap_next_ex。这一篇讲讲怎么发送数据包。
(1) pcap_loop函数调用read_op(p,cnt,callback,user);
int pcap_loop(pcap_t *p,int cnt, pcap_handler callback,u_char* user)调用read_op(p,cnt,callback,user),该函数是一个回调函数,在pcap_win32.c中有p->read_op=pcap_read_win32_npf;
//pcap_loop,pcap_dispatch,pcap_next,pcap_next_ex中调用的函数
staticintpcap_read_win32_npf(pcap_t *p,intcnt,pcap_handlercallback,u_char *user)
{
intcc;
intn = 0;
registeru_char *bp, *ep;
#ifdefHAVE_REMOTE
staticintsamp_npkt; // parameter needed for sampling, with '1 out of N' method has been requested
staticstructtimevalsamp_time;// parameter needed for sampling, with '1 every N ms' method has been requested
#endif /* HAVE_REMOTE */
cc =p->cc;
if (p->cc == 0) {
/*
* Has "pcap_breakloop()" been called?
*/
if (p->break_loop) {
/*
* Yes - clear the flag that indicates that it
* has, and return -2 to indicate that we were
* told to break out of the loop.
*/
p->break_loop = 0;
return (-2);
}
/* capture the packets接收包*/
if(PacketReceivePacket(p->adapter,p->Packet,TRUE)==FALSE){
snprintf(p->errbuf,PCAP_ERRBUF_SIZE,"read error: PacketReceivePacket failed");
return (-1);
}
cc =p->Packet->ulBytesReceived;
bp =p->Packet->Buffer;
}
else
bp =p->bp;
/*
* Loop through each packet.
*/
#definebhp ((struct bpf_hdr *)bp)
ep =bp +cc;
while (1) {
registerintcaplen,hdrlen;
/*
* Has "pcap_breakloop()" been called?
* If so, return immediately - if we haven't read any
* packets, clear the flag and return -2 to indicate
* that we were told to break out of the loop, otherwise
* leave the flag set, so that the *next* call will break
* out of the loop without having read any packets, and
* return the number of packets we've processed so far.
*/
if (p->break_loop) {
if (n == 0) {
p->break_loop = 0;
return (-2);
}else {
p->bp =bp;
p->cc =ep - bp;
return (n);
}
}
if (bp >=ep)
break;
caplen =bhp->bh_caplen;
hdrlen =bhp->bh_hdrlen;
#ifdefHAVE_REMOTE
if (p->rmt_samp.method ==PCAP_SAMP_1_EVERY_N)
{
samp_npkt= (samp_npkt + 1) %p->rmt_samp.value;
// Discard all packets that are not '1 out of N'
if (samp_npkt != 0)
{
bp +=BPF_WORDALIGN(caplen +hdrlen);
continue;
}
}
if (p->rmt_samp.method ==PCAP_SAMP_FIRST_AFTER_N_MS)
{
structpcap_pkthdr *pkt_header= (structpcap_pkthdr*)bp;
// Check if the timestamp of the arrived packet is smaller than our target time
if ( (pkt_header->ts.tv_sec <samp_time.tv_sec) ||
( (pkt_header->ts.tv_sec ==samp_time.tv_sec) && (pkt_header->ts.tv_usec <samp_time.tv_usec) ) )
{
bp +=BPF_WORDALIGN(caplen +hdrlen);
continue;
}
// The arrived packet is suitable for being sent to the remote host
// So, let's update the target time
samp_time.tv_usec=pkt_header->ts.tv_usec +p->rmt_samp.value * 1000;
if (samp_time.tv_usec > 1000000)
{
samp_time.tv_sec=pkt_header->ts.tv_sec +samp_time.tv_usec / 1000000;
samp_time.tv_usec=samp_time.tv_usec % 1000000;
}
}
#endif /* HAVE_REMOTE */
/*
* XXX A bpf_hdr matches a pcap_pkthdr.
*/
(*callback)(user, (structpcap_pkthdr*)bp,bp + hdrlen);
bp +=BPF_WORDALIGN(caplen +hdrlen);
if (++n >=cnt && cnt > 0) {
p->bp =bp;
p->cc =ep - bp;
return (n);
}
}
#undefbhp
p->cc = 0;
return (n);
}
Pcap_loop函数和pcap_dispatch函数类似,都是调用pcap_read_win32_npf函数pcap_loop函数和pcap_dispatch函数的区别是,pcap_dispatch当超时时,函数就返回,pcap_loop函数只有读到cnt个数据包才返回。Pcap_next函数和pcap_next_ex函数都是调用pcap_read_win32_npf函数,pcap_next函数和pcap_next_ex函数的区别是pcap_next调用pcap_dispatch函数后才调用pcap_read_win32_npf函数,而pcap_next_ex直接调用pcap_read_win32_npf函数,增加了远程模式和读文件模式。pcap_read_win32_npf函数调用parket中PacketRecivePacket函数。
BOOLEANPacketReceivePacket(LPADAPTERAdapterObject,LPPACKETlpPacket,BOOLEANSync) //Sync=TRUE
{
BOOLEANres;
UNUSED(Sync);
TRACE_ENTER("PacketReceivePacket");
#ifdefHAVE_WANPACKET_API
if (AdapterObject->Flags ==INFO_FLAG_NDISWAN_ADAPTER)
{
lpPacket->ulBytesReceived =WanPacketReceivePacket(AdapterObject->pWanAdapter,lpPacket->Buffer,lpPacket->Length);
TRACE_EXIT("PacketReceivePacket");
returnTRUE;
}
#endif//HAVE_WANPACKET_API
#ifdefHAVE_AIRPCAP_API
if(AdapterObject->Flags ==INFO_FLAG_AIRPCAP_CARD)
{
//
// Wait for data, only if the user requested us to do that
//
if((int)AdapterObject->ReadTimeOut != -1)
{
WaitForSingleObject(AdapterObject->ReadEvent, (AdapterObject->ReadTimeOut==0)?INFINITE:AdapterObject->ReadTimeOut);
}
//
// Read the data.
// g_PAirpcapRead always returns immediately.
//
res = (BOOLEAN)g_PAirpcapRead(AdapterObject->AirpcapAd,
lpPacket->Buffer,
lpPacket->Length,
&lpPacket->ulBytesReceived);
TRACE_EXIT("PacketReceivePacket");
returnres;
}
#endif// HAVE_AIRPCAP_API
#ifdefHAVE_NPFIM_API
if(AdapterObject->Flags == INFO_FLAG_NPFIM_DEVICE)
{
//
// Read the data.
// NpfImReceivePacket performs its own wait internally.
//
res = (BOOLEAN)g_NpfImHandlers.NpfImReceivePackets(AdapterObject->NpfImHandle,
lpPacket->Buffer,
lpPacket->Length,
&lpPacket->ulBytesReceived);
TRACE_EXIT("PacketReceivePacket");
return res;
}
#endif// HAVE_NPFIM_API
#ifdefHAVE_DAG_API
if((AdapterObject->Flags & INFO_FLAG_DAG_CARD) || (AdapterObject->Flags & INFO_FLAG_DAG_FILE))
{
g_p_dagc_wait(AdapterObject->pDagCard, &AdapterObject->DagReadTimeout);
res = (BOOLEAN)(g_p_dagc_receive(AdapterObject->pDagCard, (u_char**)&AdapterObject->DagBuffer, (u_int*)&lpPacket->ulBytesReceived) == 0);
TRACE_EXIT("PacketReceivePacket");
return res;
}
#endif// HAVE_DAG_API
if (AdapterObject->Flags ==INFO_FLAG_NDIS_ADAPTER)
{
if((int)AdapterObject->ReadTimeOut != -1)
WaitForSingleObject(AdapterObject->ReadEvent, (AdapterObject->ReadTimeOut==0)?INFINITE:AdapterObject->ReadTimeOut);
//从驱动中读取数据包
res = (BOOLEAN)ReadFile(AdapterObject->hFile,lpPacket->Buffer,lpPacket->Length, &lpPacket->ulBytesReceived,NULL);
}
else
{
TRACE_PRINT1("Request to read on an unknown device type (%u)",AdapterObject->Flags);
res =FALSE;
}
TRACE_EXIT("PacketReceivePacket");
returnres;
}
PacketReceivePacket函数ReadFile从驱动中读取数据包,应用程序和驱动进行通信到最下一层都是通过DeviceIoControl,ReadFile,WriteFile函数。这些函数在上面都已经介绍了。ReadFile对应驱动程序中
NTSTATUSNPF_Read(INPDEVICE_OBJECTDeviceObject,INPIRPIrp)
{
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;
structbpf_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); //获取Irp当前堆栈
Open=IrpSp->FileObject->FsContext; //得到打开上下文
if (NPF_StartUsingOpenInstance(Open) ==FALSE)
{
//
// an IRP_MJ_CLEANUP was received, just fail the request
//
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status =STATUS_CANCELLED;
IoCompleteRequest(Irp,IO_NO_INCREMENT); //完成irp请求
TRACE_EXIT();
returnSTATUS_CANCELLED;
}
//
// 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)
{
NPF_StopUsingOpenInstance(Open);
// The Network adapter has been removed or diasabled
EXIT_FAILURE(0);
}
NPF_StopUsingBinding(Open);
if (Open->Size == 0)
{
NPF_StopUsingOpenInstance(Open);
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
NPF_StopUsingOpenInstance(Open);
EXIT_FAILURE(0);
}
Occupation=0;
for(i=0;i<g_NCpu;i++)
Occupation += (Open->Size -Open->CpuData[i].Free); //计算出已经占用的内核缓冲区
//See if the buffer is full enough to be copied判断缓冲区是否enough
if(Occupation <=Open->MinToCopy*g_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
#ifdefNDIS50
CurrBuff=(PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority);
#else
CurrBuff=(PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress);
#endif
if (CurrBuff ==NULL)
{
NPF_StopUsingOpenInstance(Open);
EXIT_FAILURE(0);
}
if (Open->mode &MODE_DUMP)
{
if (IrpSp->Parameters.Read.Length <sizeof(struct bpf_hdr) + 24)
{
NPF_StopUsingOpenInstance(Open);
Irp->IoStatus.Status =STATUS_BUFFER_TOO_SMALL;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
returnSTATUS_BUFFER_TOO_SMALL;
}
}
else
{
if (IrpSp->Parameters.Read.Length <sizeof(struct bpf_hdr) + 16)
{
NPF_StopUsingOpenInstance(Open);
Irp->IoStatus.Status =STATUS_BUFFER_TOO_SMALL;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
returnSTATUS_BUFFER_TOO_SMALL;
}
}
//fill the bpf header for this packet
header=(structbpf_hdr*)CurrBuff;
GET_TIME(&header->bh_tstamp,&G_Start_Time);
if(Open->mode &MODE_DUMP){
*(LONGLONG*)(CurrBuff+sizeof(structbpf_hdr)+16)=Open->DumpOffset.QuadPart;
header->bh_caplen=24;
header->bh_datalen=24;
Irp->IoStatus.Information = 24 +sizeof(structbpf_hdr);
}
else{
header->bh_caplen=16;
header->bh_datalen=16;
header->bh_hdrlen=sizeof(structbpf_hdr);
Irp->IoStatus.Information = 16 +sizeof(structbpf_hdr);
}
*(LONGLONG*)(CurrBuff+sizeof(structbpf_hdr))=Open->Npackets.QuadPart;
*(LONGLONG*)(CurrBuff+sizeof(structbpf_hdr)+8)=Open->Nbytes.QuadPart;
//reset the countetrs
NdisAcquireSpinLock( &Open->CountersLock );
Open->Npackets.QuadPart=0;
Open->Nbytes.QuadPart=0;
NdisReleaseSpinLock( &Open->CountersLock );
NPF_StopUsingOpenInstance(Open);
Irp->IoStatus.Status =STATUS_SUCCESS;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
returnSTATUS_SUCCESS;
}
// 监控模式
// The MONITOR_MODE (aka TME extensions) is not supported on
// 64 bit architectures
//
#ifdefHAVE_BUGGY_TME_SUPPORT
if(Open->mode==MODE_MON) //this capture instance is in monitor mode
{
PTME_DATAdata;
ULONGcnt;
ULONGblock_size;
PUCHARtmp;
#ifdefNDIS50
UserPointer=MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority);
#else
UserPointer=MmGetSystemAddressForMdl(Irp->MdlAddress);
#endif
if (UserPointer ==NULL)
{
NPF_StopUsingOpenInstance(Open);
EXIT_FAILURE(0);
}
if ((!IS_VALIDATED(Open->tme.validated_blocks,Open->tme.active_read))||(IrpSp->Parameters.Read.Length<sizeof(structbpf_hdr)))
{
NPF_StopUsingOpenInstance(Open);
EXIT_FAILURE(0);
}
header=(structbpf_hdr*)UserPointer;
GET_TIME(&header->bh_tstamp,&G_Start_Time);
header->bh_hdrlen=sizeof(structbpf_hdr);
//moves user memory pointer
UserPointer+=sizeof(structbpf_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(structbpf_hdr))<bytecopy)
bytecopy=(IrpSp->Parameters.Read.Length-sizeof(structbpf_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;
NPF_StopUsingOpenInstance(Open);
EXIT_SUCCESS(bytecopy+sizeof(structbpf_hdr));
}
//end of //this capture instance is in monitor mode
Occupation=0;
//重新计算内核缓冲区的占用;
for(i=0;i<g_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.
{
NPF_StopUsingOpenInstance(Open);
EXIT_SUCCESS(0);
}
#else// not HAVE_BUGGY_TME_SUPPORT
if(Open->mode==MODE_MON) //this capture instance is in monitor mode
{
NPF_StopUsingOpenInstance(Open);
EXIT_FAILURE(0);
}
#endif// HAVE_BUGGY_TME_SUPPORT
}
//------------------------------------------------------------------------------
copied=0;
count=0;
current_cpu=0;
available =IrpSp->Parameters.Read.Length;
#ifdefNDIS50
packp=(PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority);
#else
packp=(PUCHAR)MmGetSystemAddressForMdl(Irp->MdlAddress);
#endif
if (packp ==NULL)
{
NPF_StopUsingOpenInstance(Open);
EXIT_FAILURE(0);
}
if (Open->ReadEvent !=NULL)
KeClearEvent(Open->ReadEvent);
while (count <g_NCpu)//round robin on the CPUs, if count = NCpu there are no packets left to be copied
{
if (available ==copied)
{
NPF_StopUsingOpenInstance(Open);
EXIT_SUCCESS(copied);
}
LocalData = &Open->CpuData[current_cpu];
if (LocalData->Free <Open->Size)
{ //there are some packets in the selected (aka LocalData) buffer
structPacketHeader *Header = (structPacketHeader*)(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
//如果包没有拷贝到用户缓冲区,结束拷贝数据包
NPF_StopUsingOpenInstance(Open);
EXIT_SUCCESS(copied);
}
// FIX_TIMESTAMPS(&Header->header.bh_tstamp);
*((structbpf_hdr*)(&packp[copied]))=Header->header;
copied +=sizeof(structbpf_hdr);
LocalData->C +=sizeof(structPacketHeader);
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(structPacketHeader);
if (Open->Size -LocalData->C <sizeof(structPacketHeader))
{ //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)%g_NCpu;
count++;
}
}
else
{
current_cpu=(current_cpu+1)%g_NCpu;
count++;
}
}
{
NPF_StopUsingOpenInstance(Open);
EXIT_SUCCESS(copied);
}
}
讲到这里,大家都知道,应用程序怎么从驱动中读取数据了,但是数据怎么到达内核缓冲区呢,下面介绍一个回调函数,NPF_tap()
NDIS_STATUSNPF_tap (IN NDIS_HANDLEProtocolBindingContext,INNDIS_HANDLEMacReceiveContext,
INPVOIDHeaderBuffer,INUINTHeaderBufferSize,INPVOIDLookaheadBuffer,
INUINTLookaheadBufferSize,INUINTPacketSize)
{
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;
structPacketHeader *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)
{
#ifdef HAVE_BUGGY_TME_SUPPORT
fres=bpf_filter_with_2_buffers((structbpf_insn*)(Open->bpfprogram),
HeaderBuffer,
LookaheadBuffer,
HeaderBufferSize,
PacketSize+HeaderBufferSize,
LookaheadBufferSize+HeaderBufferSize,
&Open->mem_ex,
&Open->tme,
&G_Start_Time);
#else// HAVE_BUGGY_TME_SUPPORT
fres=bpf_filter_with_2_buffers((structbpf_insn*)(Open->bpfprogram),
HeaderBuffer,
LookaheadBuffer,
HeaderBufferSize,
PacketSize+HeaderBufferSize,
LookaheadBufferSize+HeaderBufferSize);
#endif// HAVE_BUGGY_TME_SUPPORT
}
else
//
// the jit filter is available on x86 (32 bit) only
//
#ifdef_X86_
if(Open->Filter !=NULL)
{
if (Open->bpfprogram !=NULL)
{
fres=Open->Filter->Function(HeaderBuffer,
PacketSize+HeaderBufferSize,
LookaheadBufferSize+HeaderBufferSize);
}
else
fres = -1;
}
else
#endif//_X86_
#ifdefHAVE_BUGGY_TME_SUPPORT
fres=bpf_filter((structbpf_insn*)(Open->bpfprogram),
HeaderBuffer,
PacketSize+HeaderBufferSize,
LookaheadBufferSize+HeaderBufferSize,
&Open->mem_ex,
&Open->tme,
&G_Start_Time);
#else//HAVE_BUGGY_TME_SUPPORT
fres=bpf_filter((structbpf_insn*)(Open->bpfprogram),
HeaderBuffer,
PacketSize+HeaderBufferSize,
LookaheadBufferSize+HeaderBufferSize);
#endif//HAVE_BUGGY_TME_SUPPORT
NdisReleaseSpinLock(&Open->MachineLock);
//
// The MONITOR_MODE (aka TME extensions) is not supported on
// 64 bit architectures
//
#ifdefHAVE_BUGGY_TME_SUPPORT
if(Open->mode==MODE_MON)
// we are in monitor mode
{
if (fres==1)
{
if (Open->ReadEvent !=NULL)
{
KeSetEvent(Open->ReadEvent,0,FALSE);
}
}
returnNDIS_STATUS_NOT_ACCEPTED;
}
#endif//HAVE_BUGGY_TME_SUPPORT
if(fres==0)
{
// Packet not accepted by the filter, ignore it.
returnNDIS_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++;
if(PacketSize+HeaderBufferSize<60)
Open->Nbytes.QuadPart+=60;
else
Open->Nbytes.QuadPart+=PacketSize+HeaderBufferSize;
// add preamble+SFD+FCS to the packet
// these values must be considered because are not part of the packet received from NDIS
Open->Nbytes.QuadPart+=12;
NdisReleaseSpinLock( &Open->CountersLock );
if(!(Open->mode &MODE_DUMP))
{
returnNDIS_STATUS_NOT_ACCEPTED;
}
}
if(Open->Size == 0)
{
LocalData->Dropped++;
returnNDIS_STATUS_NOT_ACCEPTED;
}
if(Open->mode &MODE_DUMP && Open->MaxDumpPacks)
{
ULONGAccepted=0;
for(i=0;i<g_NCpu;i++)
Accepted+=Open->CpuData[i].Accepted;
if( Accepted >Open->MaxDumpPacks)
{
// Reached the max number of packets to save in the dump file. Discard the packet and stop the dump thread.
Open->DumpLimitReached =TRUE;// This stops the thread
// Awake the dump thread
NdisSetEvent(&Open->DumpEvent);
// Awake the application
if (Open->ReadEvent !=NULL)
KeSetEvent(Open->ReadEvent,0,FALSE);
returnNDIS_STATUS_NOT_ACCEPTED;
}
}
//////////////////////////////COPIA.C//////////////////////////////////////////77
ShouldReleaseBufferLock =TRUE;
NdisDprAcquireSpinLock(&LocalData->BufferLock);
do
{
if (fres +sizeof(structPacketHeader) > LocalData->Free)
{
LocalData->Dropped++;
break;
}
if (LocalData->TransferMdl1 !=NULL)
{
//
//if TransferMdl is not NULL, there is some TransferData pending (i.e. not having called TransferDataComplete, yet)
//in order to avoid buffer corruption, we drop the packet
//
LocalData->Dropped++;
break;
}
if (LookaheadBufferSize +HeaderBufferSize >= fres)
{
//
// we do not need to call NdisTransferData, either because we need only the HeaderBuffer, or because the LookaheadBuffer
// contains what we need
//
Header = (structPacketHeader*)(LocalData->Buffer +LocalData->P);
LocalData->Accepted++;
GET_TIME(&Header->header.bh_tstamp,&G_Start_Time);
Header->SN =InterlockedIncrement(&Open->WriterSN) - 1;
Header->header.bh_caplen =fres;
Header->header.bh_datalen =PacketSize + HeaderBufferSize;
Header->header.bh_hdrlen=sizeof(structbpf_hdr);
LocalData->P +=sizeof(structPacketHeader);
if (LocalData->P ==Open->Size)
LocalData->P = 0;
if (fres <=HeaderBufferSize || (UINT)( (PUCHAR)LookaheadBuffer - (PUCHAR)HeaderBuffer ) ==HeaderBufferSize )
{
//
//we can consider the buffer contiguous, either because we use only the data
//present in the HeaderBuffer, or because HeaderBuffer and LookaheadBuffer are contiguous
// ;-))))))
//
if (Open->Size -LocalData->P <fres)
{
//the packet will be fragmented in the buffer (aka, it will skip the buffer boundary)
//two copies!!
ToCopy =Open->Size -LocalData->P;
NdisMoveMappedMemory(LocalData->Buffer +LocalData->P,HeaderBuffer,ToCopy);
NdisMoveMappedMemory(LocalData->Buffer + 0 , (PUCHAR)HeaderBuffer +ToCopy,fres -ToCopy);
LocalData->P =fres-ToCopy;
}
else
{
//the packet does not need to be fragmented in the buffer (aka, it doesn't skip the buffer boundary)
// ;-)))))) only ONE copy
NdisMoveMappedMemory(LocalData->Buffer +LocalData->P,HeaderBuffer,fres);
LocalData->P +=fres;
}
}
else
{
//HeaderBuffer and LookAhead buffer are NOT contiguous,
//AND, we need some bytes from the LookaheadBuffer, too
if (Open->Size -LocalData->P <fres)
{
//the packet will be fragmented in the buffer (aka, it will skip the buffer boundary)
if (Open->Size -LocalData->P >=HeaderBufferSize)
{
//HeaderBuffer is NOT fragmented
NdisMoveMappedMemory(LocalData->Buffer +LocalData->P,HeaderBuffer,HeaderBufferSize);
LocalData->P +=HeaderBufferSize;
if (LocalData->P ==Open->Size)
{
//the fragmentation of the packet in the buffer is the same fragmentation
//in HeaderBuffer+LookaheadBuffer
LocalData->P=0;
NdisMoveMappedMemory(LocalData->Buffer + 0,LookaheadBuffer, fres -HeaderBufferSize);
LocalData->P += (fres -HeaderBufferSize);
}
else
{
//LookAheadBuffer is fragmented, two copies
ToCopy =Open->Size -LocalData->P;
NdisMoveMappedMemory(LocalData->Buffer +LocalData->P,LookaheadBuffer,ToCopy);
LocalData->P=0;
NdisMoveMappedMemory(LocalData->Buffer + 0, (PUCHAR)LookaheadBuffer+ToCopy,fres -HeaderBufferSize -ToCopy);
LocalData->P =fres - HeaderBufferSize -ToCopy;
}
}
else
{
//HeaderBuffer is fragmented in the buffer (aka, it will skip the buffer boundary)
//two copies to copy the HeaderBuffer
ToCopy =Open->Size -LocalData->P;
NdisMoveMappedMemory(LocalData->Buffer +LocalData->P,HeaderBuffer,ToCopy);
LocalData->P = 0;
NdisMoveMappedMemory(LocalData->Buffer + 0, (PUCHAR)HeaderBuffer +ToCopy,HeaderBufferSize -ToCopy);
LocalData->P =HeaderBufferSize - ToCopy;
//only one copy to copy the LookaheadBuffer
NdisMoveMappedMemory(LocalData->Buffer +LocalData->P,LookaheadBuffer,fres-HeaderBufferSize);
LocalData->P += (fres -HeaderBufferSize);
}
}
else
{
//the packet won't be fragmented in the destination buffer (aka, it won't skip the buffer boundary)
//two copies, the former to copy the HeaderBuffer, the latter to copy the LookaheadBuffer
NdisMoveMappedMemory(LocalData->Buffer +LocalData->P,HeaderBuffer,HeaderBufferSize);
LocalData->P +=HeaderBufferSize;
NdisMoveMappedMemory(LocalData->Buffer +LocalData->P,LookaheadBuffer,fres -HeaderBufferSize);
LocalData->P += (fres -HeaderBufferSize);
}
}
increment =fres +sizeof(structPacketHeader);
if (Open->Size -LocalData->P <sizeof(structPacketHeader)) //we check that the available, AND contiguous, space in the buffer will fit
{ //the NewHeader structure, at least, otherwise we skip the producer
increment +=Open->Size-LocalData->P; //at the beginning of the buffer (p = 0), and decrement the free bytes appropriately
LocalData->P = 0;
}
InterlockedExchangeAdd(&LocalData->Free, (ULONG)(-(LONG)increment));
if(Open->Size -LocalData->Free >=Open->MinToCopy)
{
if(Open->mode &MODE_DUMP)
NdisSetEvent(&Open->DumpEvent);
else
{
if (Open->ReadEvent !=NULL)
{
KeSetEvent(Open->ReadEvent,0,FALSE);
}
}
}
break;
}
else
{
IF_LOUD(DbgPrint("TransferData!!/n");)
//ndisTransferData required
LocalData->NewP =LocalData->P;
LocalData->NewP +=sizeof(structPacketHeader);
if (LocalData->NewP ==Open->Size)
LocalData->NewP = 0;
//first of all, surely the header must be copied
if (Open->Size-LocalData->NewP >=HeaderBufferSize)
{
//1 copy!
NdisMoveMappedMemory(LocalData->Buffer +LocalData->NewP,HeaderBuffer,HeaderBufferSize);
LocalData->NewP +=HeaderBufferSize;
if (LocalData->NewP ==Open->Size)
LocalData->NewP = 0;
}
else
{
ToCopy =Open->Size -LocalData->NewP;
NdisMoveMappedMemory(LocalData->Buffer +LocalData->NewP,HeaderBuffer,ToCopy);
NdisMoveMappedMemory(LocalData->Buffer + 0, (PUCHAR)HeaderBuffer +ToCopy,HeaderBufferSize -ToCopy);
LocalData->NewP =HeaderBufferSize - ToCopy;
}
//then we copy the Lookahead buffer
if (Open->Size-LocalData->NewP >=LookaheadBufferSize)
{
//1 copy!
NdisMoveMappedMemory(LocalData->Buffer +LocalData->NewP,LookaheadBuffer,LookaheadBufferSize);
LocalData->NewP +=LookaheadBufferSize;
if (LocalData->NewP ==Open->Size)
LocalData->NewP = 0;
}
else
{
ToCopy =Open->Size -LocalData->NewP;
NdisMoveMappedMemory(LocalData->Buffer +LocalData->NewP,LookaheadBuffer,ToCopy);
NdisMoveMappedMemory(LocalData->Buffer + 0, (PUCHAR)LookaheadBuffer +ToCopy,LookaheadBufferSize -ToCopy);
LocalData->NewP =LookaheadBufferSize - ToCopy;
}
//Now we must prepare the buffer(s) for the NdisTransferData
if ((Open->Size -LocalData->NewP) >= (fres -HeaderBufferSize -LookaheadBufferSize))
{
//only 1 buffer
pMdl1 =IoAllocateMdl(
LocalData->Buffer +LocalData->NewP,
fres -HeaderBufferSize -LookaheadBufferSize,
FALSE,
FALSE,
NULL);
if (pMdl1 ==NULL)
{
IF_LOUD(DbgPrint("Error allocating Mdl1/n");)
LocalData->Dropped++;
break;
}
MmBuildMdlForNonPagedPool(pMdl1);
pMdl2=NULL;
LocalData->NewP +=fres - HeaderBufferSize -LookaheadBufferSize;
}
else
{
//2 buffers
pMdl1 =IoAllocateMdl(
LocalData->Buffer +LocalData->NewP,
Open->Size -LocalData->NewP,
FALSE,
FALSE,
NULL);
if (pMdl1 ==NULL)
{
IF_LOUD(DbgPrint("Error allocating Mdl1/n");)
LocalData->Dropped++;
break;
}
pMdl2 =IoAllocateMdl(
LocalData->Buffer + 0,
fres -HeaderBufferSize -LookaheadBufferSize - (Open->Size -LocalData->NewP),
FALSE,
FALSE,
NULL);
if (pMdl2 ==NULL)
{
IF_LOUD(DbgPrint("Error allocating Mdl2/n");)
IoFreeMdl(pMdl1);
LocalData->Dropped++;
break;
}
LocalData->NewP =fres - HeaderBufferSize -LookaheadBufferSize - (Open->Size -LocalData->NewP);
MmBuildMdlForNonPagedPool(pMdl1);
MmBuildMdlForNonPagedPool(pMdl2);
}
NdisAllocatePacket(&Status, &pPacket,Open->PacketPool);
if (Status !=NDIS_STATUS_SUCCESS)
{
IF_LOUD(DbgPrint("NPF: Tap - No free packets/n");)
IoFreeMdl(pMdl1);
if (pMdl2 !=NULL)
IoFreeMdl(pMdl2);
LocalData->Dropped++;
break;
}
if (pMdl2 !=NULL)
NdisChainBufferAtFront(pPacket,pMdl2);
NdisChainBufferAtFront(pPacket,pMdl1);
RESERVED(pPacket)->Cpu =Cpu;
LocalData->TransferMdl1 =pMdl1;
LocalData->TransferMdl2 =pMdl2;
Header = (structPacketHeader*)(LocalData->Buffer +LocalData->P);
Header->header.bh_caplen =fres;
Header->header.bh_datalen =PacketSize + HeaderBufferSize;
Header->header.bh_hdrlen=sizeof(structbpf_hdr);
/*调用NdisTransferData重新获取剩余的所需数据包,从网卡的Nic memory copy to kernel buffer。*/
NdisTransferData(
&Status,
Open->AdapterHandle,
MacReceiveContext,
LookaheadBufferSize,
fres -HeaderBufferSize -LookaheadBufferSize,
pPacket,
&BytesTransfered);
if (Status !=NDIS_STATUS_PENDING)
{
IF_LOUD(DbgPrint("NdisTransferData, not pending!/n");)
LocalData->TransferMdl1 =NULL;
LocalData->TransferMdl2 =NULL;
IoFreeMdl(pMdl1);
if (pMdl2 !=NULL )
IoFreeMdl(pMdl2);
NdisReinitializePacket(pPacket);
// Put the packet on the free queue
NdisFreePacket(pPacket);
LocalData->P =LocalData->NewP;
LocalData->Accepted++;
GET_TIME(&Header->header.bh_tstamp,&G_Start_Time);
Header->SN =InterlockedIncrement(&Open->WriterSN) - 1;
increment =fres +sizeof(structPacketHeader);
if (Open->Size -LocalData->P <sizeof(structPacketHeader))
{
increment +=Open->Size-LocalData->P;
LocalData->P = 0;
}
InterlockedExchangeAdd(&LocalData->Free, (ULONG)(-(LONG)increment));
if(Open->Size -LocalData->Free >=Open->MinToCopy)
{
if(Open->mode &MODE_DUMP)
NdisSetEvent(&Open->DumpEvent);
else
{
if (Open->ReadEvent !=NULL)
{
KeSetEvent(Open->ReadEvent,0,FALSE);
}
}
}
break;
}
else
{
IF_LOUD(DbgPrint("NdisTransferData, pending!/n");)
ShouldReleaseBufferLock =FALSE;
}
}
}
while(FALSE);
if (ShouldReleaseBufferLock)
{
NdisDprReleaseSpinLock(&LocalData->BufferLock);
}
returnNDIS_STATUS_NOT_ACCEPTED;
}
要理解这个函数涉及到Ndis驱动的内容,在这里就不详细讲解了,下一章讲解如何设置内核缓冲区,用户缓冲区等内容。