深度剖析WinPcap之(八)——打开与关闭适配器(17)

本文转自http://eslxf.blog.51cto.com/918801/209247

 

1.6      NPF中对应的函数接口

1.6.1        关键结构体 _OPEN_INSTANCE

结构体 _OPEN_INSTANCE包含NPF驱动程序一个运行实例的状态;这是NPF最重要的结构体:它被几乎所有驱动程序的函数使用;一个_OPEN_INSTANCE结构体与每个用户层会话关联,并允许对该驱动程序的并发访问。
结构体的具体定义如下:
typedef struct _OPEN_INSTANCE
{
    PDEVICE_EXTENSION   DeviceExtension;    //指向该实例所缚设备的_DEVICE_EXTENSION结构体的指针
    NDIS_HANDLE         AdapterHandle;      //该实例使用适配器的NDIS标识符
    UINT                Medium;             //底层NDIS驱动使用的物理媒体类型。
//参见微软WDKNdisOpenAdapter()函数的文档了解详情。
    NDIS_HANDLE         PacketPool;         //NDIS_PACKET结构体的存储池,
//用来与NIC驱动传输数据包。
    KSPIN_LOCK         RequestSpinLock;    //用来同步OID请求的自旋锁
    LIST_ENTRY          RequestList;        // 挂起的OID请求列表
    LIST_ENTRY          ResetIrpList;       //挂起的适配器复位请求列表
    INTERNAL_REQUEST    Requests[MAX_REQUESTS]; //封装每单个OID请求的结构体数组
    PMDL                BufferMdl;          //指向一个内存描述列表(MDL)的指针,
//MDL映射了环形缓冲区的内存
    PKEVENT             ReadEvent;      //指向事件的指针,在该事件上对该实例的读调用必须等待   
    PUCHAR              bpfprogram;     //指向与当前实例相关的过滤伪代码的指针
                                        //该代码只能在特定情景中使用(例如,当从NIC驱动程序接收的数据包存储在两个非连续的缓冲区中。)在正常情况下,使用被JIT编译器创建并被下一个字段(Filter)所指向的 过滤例程。参见NPF了解过滤过程的细节。
#ifdef _X86_
    JIT_BPF_Filter      *Filter;            //指向由jitter所创建的本机过滤函数的指针。参见BPF_jitter()函数了解细节。
#endif //_X86_
    UINT                MinToCopy;          //环形缓冲区中没被锁定的最小可读的数据数量,通过IOCTLBIOCSMINTOCOPY控制码设置
    LARGE_INTEGER       TimeOut;            //读操作的超时值,即使缓冲区的数据数量低于MinToCopy(通过IOCTL控制码 BIOCSRTIMEOUT设置),读操作也返回。int                  mode;               //驱动程序的工作模式。参见PacketSetMode()函数了解细节
    LARGE_INTEGER       Nbytes;             //当该实例在统计模式下时,记录被过滤器接收的字节数量。
    LARGE_INTEGER       Npackets;           //当该实例在统计模式下时,记录被过滤器接收的数据包数量。
    NDIS_SPIN_LOCK      CountersLock;       //保护统计模式计数器的自旋锁
    UINT                Nwrites;            //一个数据包需要被重复发送的次数。参见NPF了解细节
    ULONG               Multiple_Write_Counter; //对一个单个写操作已做物理重复的次数进行计数
    NDIS_EVENT          WriteEvent;     //同步多个写进程的事件
    BOOLEAN             WriteInProgress;    //如果正在写的过程中为TRUENPF当前允许在同一个open实例上执行一个单独的写操作
    NDIS_SPIN_LOCK      WriteLock;      //保护WriteInProgress 变量的自旋锁
    NDIS_EVENT          NdisRequestEvent;   //用来同步NDIS的回调结构体与I/O请求的事件
    BOOLEAN             SkipSentPackets;    //如果该实例不应该捕获它自己所传输的数据包,则为True
    NDIS_STATUS         IOStatus;           //维护OID请求调用的状态 ,这将传递给应用程序
    HANDLE              DumpFileHandle;     //在转储模式下使用的文件句柄
    PFILE_OBJECT        DumpFileObject;     //指向转储模式下使用的文件对象的指针
    PKTHREAD            DumpThreadObject;   //指向转储模式下使用的线程对象的指针
    HANDLE              DumpThreadHandle;   //转储模式下创建的线程句柄,为了异步地把数据从缓冲区搬移到磁盘
    NDIS_EVENT          DumpEvent;          //转储模式下,用来同步转储线程与探针(tap)读取的事件
    LARGE_INTEGER       DumpOffset;         //转储文件当前的偏移
    UNICODE_STRING      DumpFileName;       //转储文件的文件名
    UINT                MaxDumpBytes;       //转储文件的能存储的最大字节数。如果转储文件达到该大小限定,它将被关闭 。0值意味着无大小限制。
    UINT                MaxDumpPacks;       //所能存储到转储文件中最大的数据包包数,如果转储文件达到该限定,它将被关闭 。0值意味着无此限制。
    BOOLEAN             DumpLimitReached;   //如果转储文件的最大大小(MaxDumpBytesMaxDumpPacks)达到了,该值为TRUE
#ifdef HAVE_BUGGY_TME_SUPPORT
    MEM_TYPE            mem_ex;     //TME虚拟协处理器使用的内存  
TME_CORE            tme;        //包含TME协处理器虚拟机的数据结构体
#endif //HAVE_BUGGY_TME_SUPPORT
    NDIS_SPIN_LOCK      MachineLock;//保护BPF过滤器与TME引擎的自旋锁,如果在使用中
    UINT                MaxFrameSize;       //底层MAC所能接收的最大帧大小。用来检测通过NPF_Write()NPF_BufferedWrite()发送的帧大小。
    // KAFFINITY被用来作为一个位掩码,是为了系统的亲缘性。因此在每个被支持的操作系统上对所有系统上的CPU都是足够大的(x86上为32位,x64上为64?.
//我们使用它的大小计算CPU的最大数目。
    CpuPrivateData      CpuData[sizeof(KAFFINITY) * 8];     //内核缓冲区结构体的内存池,每个CPU一个
    ULONG               ReaderSN;           //下一个将被从内核缓冲池中读取的数据包的序号
    ULONG               WriterSN;           //下一个将被写入内核缓冲池中的数据包的序号。
//这两个序号对每个捕获实例都是唯一的。
    ULONG               Size;           //包含在CpuData字段中的每个内核缓冲区的大小
    ULONG              AdapterHandleUsageCounter;
    NDIS_SPIN_LOCK     AdapterHandleLock;
    ULONG              AdapterBindingStatus;    ////描述NPF是否仍然被该实例使用的适配器所束缚,它是未绑定的或它是未束缚的。
    NDIS_EVENT         NdisOpenCloseCompleteEvent;
    NDIS_EVENT         NdisWriteCompleteEvent;  //事件,当所有数据包被NdisSend成功发送后产生该事件通知(并且,对应的sendComplete函数被调用)
    NTSTATUS           OpenCloseStatus;
    ULONG              TransmitPendingPackets;  //说明正被挂起的待传输数据包的数目,比如,已被提交给NdisSendXXX,但是SendComplete仍没被调用。
}OPEN_INSTANCE, *POPEN_INSTANCE;
 
其中Requests[MAX_REQUESTS]的类型为INTERNAL_REQUEST结构体,该结构体存储一个OID请求。驱动程序使用该结构体在底层NIC驱动程序上执行OID请求或者设置操作。通常仅网络驱动程序执行OID操作,但NPF通过一个IOCTL接口导出该机制给用户层应用程序。驱动程序使用该结构体来封装一个NDIS_REQUEST结构体。
结构体的具体定义如下:
typedef struct _INTERNAL_REQUEST {
    LIST_ENTRY  ListElement;        //用来操控请求链表的句柄
    NDIS_EVENT  InternalRequestCompletedEvent;//请求完成事件
    NDIS_REQUEST    Request;    //带有实际请求的结构体,将由NdisRequest调用传递。
    NDIS_STATUS RequestStatus;
} INTERNAL_REQUEST, *PINTERNAL_REQUEST;
 
NPF 有四种工作模式,分别定义如下:
#define MODE_CAPT 0x0        // 捕获工作模式
#define MODE_STAT 0x1        // 统计工作模式
#define MODE_MON  0x2        // 内核监视模式
#define MODE_DUMP 0x10       // 内核转储工作模式

1.6.2    IRP的说明

NPF驱动程序入口DriverEntry中的下列代码指定了IRP_MJ_CREATEIRP_MJ_CLOSEIRP_MJ_CLEANUPIRP_MJ_DEVICE_CONTROLIRP对应的处理函数。
DriverObject->MajorFunction[IRP_MJ_CREATE] = NPF_Open;
DriverObject->MajorFunction[IRP_MJ_CLOSE]  = NPF_Close;
DriverObject->MajorFunction[IRP_MJ_CLEANUP]= NPF_Cleanup;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = NPF_IoControl;
 
函数PacketOpenAdapterNPFCreateFileA系统调用导致NPF_Open函数调用。
lpAdapter->hFile=CreateFileA(SymbolicLinkA,
GENERIC_WRITE | GENERIC_READ,0,NULL,OPEN_EXISTING,0,0);
 
函数PacketCloseAdapterCloseHandle系统调用导致NPF_CleanupNPF_Close函数调用。
CloseHandle(lpAdapter->hFile);
 
诸如PacketSetBuff函数中DeviceIoControl的系统调用导致NPF_IoControl函数调用。
Result = (BOOLEAN)DeviceIoControl(AdapterObject->hFile,
BIOCSETBUFFERSIZE,&dim,sizeof(dim),
NULL,0,&BytesReturned,NULL);
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值