庖丁解牛-----winpcap源码彻底解密(三)

来源:互联网 发布:excel数据分析描述统计 编辑:程序博客网 时间:2024/05/19 06:47

庖丁解牛-----winpcap源码彻底解密(三)

  上一篇讲了怎么发送数据包,这次接着讲怎么接收数据包,数据包过滤后,就被复制到内核缓冲区(kernel buffer),接收数据包的方式有2种,使用回调函数接收数据包,比如pcap_looppcap_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函数调用parketPacketRecivePacket函数。

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从驱动中读取数据包,应用程序和驱动进行通信到最下一层都是通过DeviceIoControlReadFileWriteFile函数。这些函数在上面都已经介绍了。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驱动的内容,在这里就不详细讲解了,下一章讲解如何设置内核缓冲区,用户缓冲区等内容。

原创粉丝点击