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

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

 

1.5      packet.dll对应的函数接口

下面对各函数在packet.dll中的实现进行详细分析。

1.5.1        关键结构体

结构体_ADAPTER描述了一个打开的适配器,该结构体对packet.dll的函数非常重要,不过大部分成员对用户而言都可不用关心,因为该库原本就是为了避免用户处理底层的参数而设计的。该结构体的定义如下:
typedef struct _ADAPTER  {
    HANDLE hFile;               //指向一个NPF驱动程序实例的句柄
    CHAR  SymbolicLink[MAX_LINK_NAME_LENGTH]; //保存当前打开网络适配器的名称
    int NumWrites;              //对每个数据包重复发送的次数
    HANDLE ReadEvent;           //与适配器上读调用关联的通知事件
    UINT ReadTimeOut;           //读超时时间
    CHAR Name[ADAPTER_NAME_LENGTH];
    PWAN_ADAPTER pWanAdapter;
    UINT Flags;                 //适配器标识
}  ADAPTER, *LPADAPTER;
结构体_PACKET包含了从驱动程序来的一组数据包。该结构体定义了与每个递送给应用程序的数据包相关联的包头。结构体的定义如下:
typedef struct _PACKET { 
    PVOID        Buffer;        //存储数据包的缓冲区。参见PacketReceivePacket()了解缓冲区中的数据组织形式。
    UINT         Length;        //缓冲区的长度
    DWORD        ulBytesReceived;   //缓冲区中的有效字节数,如最后调用PacketReceivePacket所接收的数据量
}  PACKET, *LPPACKET;
结构体_PACKET_OID_DATA包含一个OID请求。它被PacketRequest函数使用来发送一个OID请求给接口卡驱动程序。它也能被用来获取诸如适配器的错误计数、MAC地址、多播列表,等信息。结构体的定义如下:
struct _PACKET_OID_DATA {
    ULONG Oid;                  //OID码。 参见Microsoft DDK文档或文件 ntddndis.h获得一个有效编码的完整列表。
    ULONG Length;               //Data成员的长度。
UCHAR Data[1];              //变长成员,包含传递到适配器或从适配器接收的信息
};
typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA;

1.5.2        PacketOpenAdapter函数

在库wpcap.dllpcap_activate_win32()函数调用PacketOpenAdapter()函数打开适配器。函数PacketOpenAdapter()的作用就是打开一个适配器。函数原型如下:
LPADAPTER PacketOpenAdapter(PCHAR AdapterNameWA)
参数AdapterNameWA字符串包含待打开设备的名称。函数调用PacketOpenAdapterNPF()函数获取可用的设备列表。
函数如果成功,返回一个已经正确初始化的ADAPTER对象的指针。否则返回NULL
函数的主要代码如下:
LPADAPTER PacketOpenAdapter(PCHAR AdapterNameWA)
{
    …
    /*检查适配器的名称是否为ASCII码字符串,如果不是,执行转换*/
    if(AdapterNameWA[1]!=0)
    {   //ASCII码字符串
        bFreeAdapterNameA = FALSE;
        AdapterNameA = AdapterNameWA;
    }
    else
    {   //Unicode码字符串,转换为ASCII码字符串
        size_t bufferSize = wcslen((PWCHAR)AdapterNameWA) + 1;
        AdapterNameA = GlobalAllocPtr(GPTR, bufferSize);
 
        if (AdapterNameA == NULL)
        {//分配错误,函数返回
            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
            return NULL;
        }
 
        StringCchPrintfA(AdapterNameA, bufferSize, "%ws",
                            (PWCHAR)AdapterNameWA);
        bFreeAdapterNameA = TRUE;
    }
/*获得g_AdaptersInfoMutex互斥信号*/
    WaitForSingleObject(g_AdaptersInfoMutex, INFINITE);
   
/*查找适配器,并打开它*/
    do
    {  
        //第一次查找给定适配器的PADAPTER_INFO结构体
        TAdInfo = PacketFindAdInfo(AdapterNameA);
        if(TAdInfo == NULL)
        {//没有找到,更新链表,然后执行第二次查找
            PacketUpdateAdInfo(AdapterNameA);
            TAdInfo = PacketFindAdInfo(AdapterNameA);
        }
 
        if(TAdInfo == NULL)
        {//出错处理,跳出do…while循环
            break;
        }
 
   
//找到适配器,检查适配器的类型,查看它是否被正确的支持,
//此处我们只考虑正常的NPF适配器
#ifdef HAVE_WANPACKET_API
        if(TAdInfo->Flags == INFO_FLAG_NDISWAN_ADAPTER)
        {
            …
            break;
        }
#endif //HAVE_WANPACKET_API
 
        if(TAdInfo->Flags == INFO_FLAG_DONT_EXPORT)
        {
            //该适配器不允许被导出,跳出循环
… 
break;
        }
       
        if (TAdInfo->Flags != INFO_FLAG_NDIS_ADAPTER)
        {//打开不明标识的适配器,跳出循环
            break;
        }
 
        //正常的NPF适配器,试图打开它  
        lpAdapter = PacketOpenAdapterNPF(AdapterNameA);
        if (lpAdapter == NULL)
        {//打开失败
            dwLastError = GetLastError();
        }
 
    }while(FALSE);
 
/*释放g_AdaptersInfoMutex互斥信号*/
    ReleaseMutex(g_AdaptersInfoMutex);
 
   /*如果执行了Unicode转换,释放所用的内存*/
    if (bFreeAdapterNameA)
GlobalFree(AdapterNameA);
 
   /*函数返回*/
    if (dwLastError != ERROR_SUCCESS)
    {//函数失败,返回NULL
        SetLastError(dwLastError);
        return NULL;
    }
    else
    {//函数成功,返回所打开的适配器关联的结构体指针
        return lpAdapter;
    }
}
函数首先检查适配器的名称是否为ASCII码字符串,如果不是,执行Unicode码到ASCII码的转换。
然后获得g_AdaptersInfoMutex互斥信号,调用PacketFindAdInfo()函数开始在g_AdaptersInfoList链表中查找适配器。如果第一次没有查到,调用PacketUpdateAdInfo()函数更新该链表,执行第二次查找。
如果找到适配器,检查适配器的类型,查看它是否被正确的支持,我们只考虑正常的NPF适配器。
如果是正常的NPF适配器,调用PacketOpenAdapterNPF()函数打开它。 
然后释放g_AdaptersInfoMutex互斥信号,如果执行了Unicode转换,释放所用的内存。
最后,如果函数成功,则返回与打开适配器关联的结构体指针lpAdapter,否则返回NULL

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值