1.4.2.3 pcap_activate_win32函数
在函数pcap_create()中把p->activate_op操作句柄设为 pcap_activate_win32()函数。函数pcap_activate_win32()为激活捕捉实例做各种准备工作。
函数的主要代码如下:
static
int pcap_activate_win32(pcap_t *p)
{
NetType type;
/*
初始化WinSock*/
wsockinit();
/*
调用packet.dll的函数PacketOpenAdapter()打开适配器*/
p->adapter = PacketOpenAdapter(p->opt.source);
if (p->adapter == NULL)
{//
错误,函数返回
…
}
/*
调用packet.dll的函数PacketGetNetType()获取网络类型*/
if(PacketGetNetType (p->adapter,&type) == FALSE)
{
//
错误,函数返回
…
}
/*
设置链路类型*/
switch (type.LinkType)
{
case NdisMediumWan:
p->linktype = DLT_EN10MB;
break;
case NdisMedium802_3:
p->linktype = DLT_EN10MB;
/*
*
这大概是一个真正的以太网捕获;给它数据链路层类型链表设置为DLT_EN10MB与 DLT_DOCSIS,因此一个应用程序可以让你选择它的类型,以防万一正在捕获DOCSIS网络数据包,是由一个Cisco网线调制器终端系统发送到以太网上的(它不发送一个以太网协议头到线上,而是发送原始的DOCSIS数据帧到线上)。
*/
p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
/*
如果分配失败,仅留下空链表*/
if (p->dlt_list != NULL) {
p->dlt_list[0] = DLT_EN10MB;
p->dlt_list[1] = DLT_DOCSIS;
p->dlt_count = 2;
}
break;
…
default:
p->linktype = DLT_EN10MB; /*
一个未知的适配器假定为以太网适配器*/
break;
}
/*
设置网络适配器的过滤模式为混杂模式*/
if (p->opt.promisc)
{//
混杂模式
if (PacketSetHwFilter(p->adapter,
NDIS_PACKET_TYPE_PROMISCUOUS) == FALSE)
{
//
错误,函数返回
…
}
}
else
{//
非混杂模式
if (PacketSetHwFilter(p->adapter,
NDIS_PACKET_TYPE_ALL_LOCAL) == FALSE)
{
//
错误,函数返回
…
}
}
/*
设置pcap_t结构体中的缓冲区大小*/
p->bufsize = WIN32_DEFAULT_USER_BUFFER_SIZE;
/*
分配在捕获过程中使用的数据包结构体*/
if((p->Packet = PacketAllocatePacket())==NULL)
{
//
错误,函数返回
…
}
if(!(p->adapter->Flags & INFO_FLAG_DAG_CARD))
{
/*
*
传统的适配器
*/
/*
*
如果缓冲区的大小不是显式的设定,默认为 WIN32_DEFAULT_USER_BUFFER_SIZE。
*/
if (p->opt.buffer_size == 0)
p->opt.buffer_size = WIN32_DEFAULT_KERNEL_BUFFER_SIZE;
//
设置内核NPF的缓冲区
if(PacketSetBuff(p->adapter,p->opt.buffer_size)==FALSE)
{
//
错误,函数返回
…
}
p->buffer = (u_char *)malloc(p->bufsize);
if (p->buffer == NULL)
{
//
错误,函数返回
…
}
/*
初始化捕获过程中使用的数据包结构体*/
PacketInitPacket(p->Packet,(BYTE*)p->buffer,p->bufsize);
/*
告诉驱动程序 只有存储了至少16K的数据后,才能复制数据*/
if(PacketSetMinToCopy(p->adapter,16000)==FALSE)
{
//
错误,函数返回
…
}
}
/*
设置读取超时时间*/
PacketSetReadTimeout(p->adapter, p->md.timeout);
/*
设置常规的NPF进行读取与设置过滤的操作句柄*/
p->read_op = pcap_read_win32_npf;
p->setfilter_op = pcap_setfilter_win32_npf;
p->setdirection_op = NULL; /*
没有实现*/
p->inject_op = pcap_inject_win32;/*
发送单个数据包的操作*/
p->set_datalink_op = NULL; /*
不能改变数据链路层的类型*/
p->getnonblock_op = pcap_getnonblock_win32;
p->setnonblock_op = pcap_setnonblock_win32;
p->stats_op = pcap_stats_win32;
p->setbuff_op = pcap_setbuff_win32;
p->setmode_op = pcap_setmode_win32;
p->setmintocopy_op = pcap_setmintocopy_win32;
p->cleanup_op = pcap_cleanup_win32;
return (0);
bad:
pcap_cleanup_win32(p);
return (PCAP_ERROR);
函数首先调用wsockinit()函数初始化WinSock,然后调用packet.dll提供的函数PacketOpenAdapter()打开适配器。
接着调用packet.dll提供的函数PacketGetNetType()获取网络类型。根据网络类型设置链路类型。此处我们只分析常规的以太网捕获。
接下来调用packet.dll提供的函数PacketSetHwFilter()设置网络适配器的过滤模式为混杂模式。
然后设置用户层与内核捕获数据的缓冲区大小分别为WIN32_DEFAULT_USER_BUFFER_SIZE(256KB)与WIN32_DEFAULT_KERNEL_BUFFER_SIZE(1MB),并设置内核缓冲区,分配用户缓冲区,并进行初始化。
设置驱动程序只有存储了至少16K的数据后,才能复制数据到用户空间,设置读取超时时间。
设置NPF进行读取的操作句柄为pcap_read_win32_npf()函数与设置过滤的操作句柄为pcap_setfilter_win32_npf函数。
设置发送单个数据包的操作句柄为pcap_inject_win32函数。设置下列函数句柄。
p->getnonblock_op = pcap_getnonblock_win32;
p->setnonblock_op = pcap_setnonblock_win32;
p->stats_op = pcap_stats_win32;
p->setbuff_op = pcap_setbuff_win32;
p->setmode_op = pcap_setmode_win32;
p->setmintocopy_op = pcap_setmintocopy_win32;
p->cleanup_op = pcap_cleanup_win32;
最后函数返回 。
其中函数wsockinit()主要调用WSAStartup()系统函数实现Winsocket的初始化。
把p->cleanup_op清除操作设置为
pcap_cleanup_win32 ()
函数,使得与pcap_open_live()函数对应的pcap_close()函数调用,调用该函数正确释放各种资源。