您的位置:首页 > 其它

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

2010-06-23 00:02 330 查看
本文转自http://eslxf.blog.51cto.com/918801/205038



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()函数调用,调用该函数正确释放各种资源。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: